F# 查询表达式产量

标签 f# f#-3.0 computation-expression query-expressions

我在学习 F#现在正在阅读有关与 SQL 类型提供程序一起使用的计算表达式和查询表达式。我正在做一些简单的任务,在阅读了有关 yield 之后,我的第一个想法是在某些时候需要连接(联合)2 个查询。在序列和列表中是在这样的查询表达式中做同样的事情:

query {
    yield! for a in db.As select { // projection }
    yield! for b in db.Bs select { // projection }
}

这是无效代码,然后我的第二种方法是使用以下方法“连接”它们:
seq {
    yield! query {...}
    yield! query {...}
}

或使用 Linq 的 Concat功能如下:(query {...}).Concat(query {...}) .怎么做来自这个question的回答

尽管使用 seq,但上述两种方法都有一个区别。将运行 2 个 SQL 查询,以及 Concat只运行一个可以理解的。

我的问题是:为什么不是 yield支持查询表达式?

编辑:

经过进一步调查,我找到了 MSDN docs我看到了 YieldYieldFrom方法已实现,但未实现 CombineDelay方法,现在对我来说更令人困惑

最佳答案

yield!在查询中一定程度上支持,可以在select处使用通常是:

query { 
    for x in [5;2;0].AsQueryable() do 
    where (x > 1)
    sortBy x
    yield! [x; x-1] 
 } |> Seq.toList // [2;1;5;4]

但是,通常您不能随意散布查询和序列操作,因为很难定义它们应该如何组合:
query {
    for x in [1;2;3] do
    where (x > 1)
    while true do // error: can't use while (what would it mean?)
    sortBy x 
}

同样地:
query {
    for x in [1;2;3] do
    where (x > 1)
    sortBy x 
    yield! ['a';'b';'c']
    yield! ['x';'y';'z'] // error
}        

这有点模棱两可,因为不清楚第二个 yield! 是否是在 for 里面循环或之后附加一组元素。

因此最好将查询视为查询,将序列视为序列,即使两种计算表达式都支持某些相同的操作。

通常,查询自定义运算符按元素工作,因此表达诸如联合或连接之类的内容很尴尬,因为它们处理整个集合而不是单个元素。但是,如果您愿意,可以创建一个添加了 concat 的查询构建器。采用序列的自定义运算符,尽管它可能感觉有点不对称:
open System.Linq

type QB() =
    member inline x.Yield v = (Seq.singleton v).AsQueryable()
    member inline x.YieldFrom q = q
    [<CustomOperation("where", MaintainsVariableSpace=true)>]
    member x.Where(q:IQueryable<_>, [<ProjectionParameter>]c:Expressions.Expression<System.Func<_,_>>) = q.Where(c)
    [<CustomOperation("sortBy", MaintainsVariableSpace=true)>]
    member x.SortBy(q:IQueryable<_>, [<ProjectionParameter>]c:Expressions.Expression<System.Func<_,_>>) = q.OrderBy(c)
    [<CustomOperation("select")>]
    member x.Select(q:IQueryable<_>, [<ProjectionParameter>]c:Expressions.Expression<System.Func<_,_>>) = q.Select(c)
    [<CustomOperation("concat")>]
    member x.Concat(q:IQueryable<_>, q') = q.Concat(q')
    member x.For(q:IQueryable<'t>, c:'t->IQueryable<'u>) = q.SelectMany(fun t -> c t :> seq<_>) // TODO: implement something more reasonable here

let qb = QB()

qb {
    for x in ([5;2;0].AsQueryable()) do
    where (x > 1)
    sortBy x
    select x
    concat ([7;8;9].AsQueryable())
} |> Seq.toList

关于F# 查询表达式产量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33219199/

相关文章:

f# - Trial.lift 和 Trial.bind 在 chessie 错误处理中的区别是什么?

使用记录类型的 F# WebApi 未提供所需的 XML 输出

嵌套 bool 测试的 F# 计算表达式?

f# - 使用零的计算表达式

design-patterns - 如何创建函数集合?

f# 类型提供程序和 INPC 元编程

json - 通过 FsCheck 生成 Json 数组

f# - 如何在 F# 中将引用编译为新类型的公共(public)静态方法

data-structures - F# 用于高频实时流数据的不可变数据结构

f# - 计算表达式不执行 Let