F# 查询表达式中运算符的顺序
order of operators in F# query expression
查询表达式运算符的顺序重要吗? Idk,但有时(在某些 selections 中)它会,但有时它不会(或者它可能会但隐式处理某些特定情况)。
是否强制要求 select 运算符必须放在最后?在几乎所有的组合中,如果你不把它写成最后一条语句,它就会抱怨,但是在 take n 的情况下,这个运算符可以在 [=35= 之后]
我只对执行过程如何运作感兴趣?
这让我想到另一个问题。如果它遍历 Iterable 集合,因此在第一次迭代时它 select 是某个(第一个)值,那么 order 如何作用于那个(第一个)值?如果它首先返回序列,然后在该序列上执行命令,那将很清楚。但似乎它在每次迭代时都执行 sortBy(?)。我对执行算法的设计很感兴趣。
这是我的查询表达式示例。
let sq = query {
for p in datasource do
where p.age>20
sortBy p.age
select p
}
如有解释,将不胜感激。
谢谢
不用猜也能知道
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 理解无关紧要,因为查询将由表达式访问者翻译,但对于对象查询,查询表达式对您来说几乎只是语法糖。
方法二:
您可以扩展查询表达式模块以包含副作用运算符。这只是 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
上方,您会看到它反映了筛选前的那些记录。
查询表达式运算符的顺序重要吗? Idk,但有时(在某些 selections 中)它会,但有时它不会(或者它可能会但隐式处理某些特定情况)。
是否强制要求 select 运算符必须放在最后?在几乎所有的组合中,如果你不把它写成最后一条语句,它就会抱怨,但是在 take n 的情况下,这个运算符可以在 [=35= 之后]
我只对执行过程如何运作感兴趣?
这让我想到另一个问题。如果它遍历 Iterable 集合,因此在第一次迭代时它 select 是某个(第一个)值,那么 order 如何作用于那个(第一个)值?如果它首先返回序列,然后在该序列上执行命令,那将很清楚。但似乎它在每次迭代时都执行 sortBy(?)。我对执行算法的设计很感兴趣。
这是我的查询表达式示例。
let sq = query {
for p in datasource do
where p.age>20
sortBy p.age
select p
}
如有解释,将不胜感激。
谢谢
不用猜也能知道
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 理解无关紧要,因为查询将由表达式访问者翻译,但对于对象查询,查询表达式对您来说几乎只是语法糖。
方法二:
您可以扩展查询表达式模块以包含副作用运算符。这只是 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
上方,您会看到它反映了筛选前的那些记录。