F#查询表达式中的运算符顺序

时间:2016-12-08 14:45:58

标签: f# query-expressions

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

强烈要求选择运算符必须最后?如果你不把它写成最后一个陈述,它会抱怨几乎所有的组合,但是如果取n ,这个操作员可以追求选择

我只对执行过程如何行动感兴趣?

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

以下是我的查询表达示例。

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

非常感谢解释。

由于

2 个答案:

答案 0 :(得分: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理解并不重要,因为查询将由Expression访问者翻译,但对于对象查询,查询表达式几乎只是你的语法糖。

答案 1 :(得分:1)

方法#2:

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

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之上,您会在过滤前看到它会反映这些记录。