3

查询表达式运算符的顺序是否重要?Idk,但有时(在某些选择中)它会,但有时它不会(或者它可能会但隐含地处理某些特定场合)。

选择运算符必须放在最后是强制性的吗?在几乎所有组合中,如果您不将其写为最后一条语句,它就会抱怨,但在take n的情况下,此运算符可以在select之后

我只是对执行过程的行为感兴趣?

这让我想到了另一个问题。如果它遍历 Iterable 集合,因此在第一次迭代中它选择某个(第一个)值,那么顺序如何处理那个(第一个)值?如果它首先返回序列,然后在该序列上执行 order 会很清楚.. 但似乎它在每次迭代时执行sortBy (?)。我对执行算法的设计很感兴趣。

这是我的查询表达式示例。

let sq = query {
   for p in datasource do
   where p.age>20
   sortBy p.age
   select p
}

解释将不胜感激。

谢谢

4

2 回答 2

3

我们不需要猜测,我们可以找出答案。

let sample = Seq.init 10 (fun i -> i * 10) |> Seq.map (fun i -> { age =  i }) 
let sq = query {
   for p in sample do
   where (p.age > 20)       
   sortBy p.age
   select p
}

sq |> Seq.toList |> ignore

生成的 IL(已清理)看起来像

IL_004e: newobj instance void Program/sq@16::.ctor(class [FSharp.Core]Microsoft.FSharp.Linq.QueryBuilder)
IL_0053: callvirt instance [...] For<class Program/Person,      
IL_005d: callvirt instance [...] Where<class Program/Person,    
IL_0067: callvirt instance [...] SortBy<class Program/Person,   
IL_0071: callvirt instance [...] Select<class Program/Person,   

假设我们改变 sortBy 的顺序

let sq = query {
   for p in sample do
   sortBy p.age
   where (p.age > 20)       
   select p
}

新的 IL 将是:

IL_006c: callvirt instance [...] For<class Program/Person,      
IL_0076: callvirt instance [...] SortBy<class Program/Person,   
IL_0080: callvirt instance [...] Where<class Program/Person,    
IL_008a: callvirt instance [...] Select<class Program/Person,   

您可以清楚地看到它遵循您定义查询的确切顺序。这对于 T-SQL 理解无关紧要,因为查询将由表达式访问者翻译,但对于对象查询,查询表达式几乎只是语法糖为你。

于 2016-12-09T18:37:46.090 回答
1

方法#2:

您可以扩展查询表达式模块以包含用于副作用的运算符。这只是 Interactive ExtensionsDoAction方法的一个端口。

module QueryExtensions =

    type QueryBuilderEx() =
        inherit Linq.QueryBuilder()

        [<CustomOperation("doAction", MaintainsVariableSpace = true)>]
        member __.Do(source : Linq.QuerySource<'T,System.Collections.IEnumerable>, action) =            
            new Linq.QuerySource<'T,System.Collections.IEnumerable>(source.Source |> Seq.map (fun v -> action(v); v))


let query = QueryExtensions.QueryBuilderEx()

现在您可以像这样调试订单

let sq = query {
       for p in sample do
       sortBy p.age       
       where (p.age > 20)       
       doAction (printfn "Next -> %A")
       select p
    }

如果将其移到 上方where,您会看到它在过滤之前反映了这些记录。

于 2016-12-09T18:45:12.310 回答