递归查询理解(F#3.0)

Dr *_*bda 3 f#

我正在尝试使用最近引入的F#3.0查询理解语法来定义Bill of Materials类型的查询.虽然可以使用yield!seq comprehensions为内存中的集合定义这些类型的查询,但我并不缺乏将它们转换为针对远程IQueryable源的查询理解.我想最困难的部分是"训练"提供者从递归模式中识别公用表表达式.

有任何想法吗?

Tom*_*cek 5

不幸的是,我不认为F#3.0中当前的查询语法支持能够处理递归查询.主要问题是F#3.0依赖于IQueryable主要为C#设计的标准实现,因此它们不期望递归结构.

我认为支持这一点非常困难.您可以为SQL转换器实现自己的F#引用(这很难),或者您可以实现某种预处理器,它采用包含递归的F#引用(查询)并将递归转换为LINQ to SQL转换器可以转换的内容处理(但这可能很难).

通常,方法是定义自己的查询构建器:

open System.IO
open Microsoft.FSharp.Quotations

type MyQueryBuilder() =
  member x.For(a, body) = Seq.collect body a
  member x.Quote(e) = e
  member x.YieldFrom(s) = s
  member x.Run(e:Expr<'T>) : 'T = failwithf "%A" e

// Example using the custom query builder
// (fails, printing the quoted query)
let mquery = MyQueryBuilder()    
let n = [1 .. 10]

let rec nums a : seq<int> =
  mquery { for b in n do
           yield! nums b }
Run Code Online (Sandbox Code Playgroud)

在该Run方法中,您将获得表示查询的报价.您可以预处理它并将所有调用替换为MyQueryBuilder对标准query操作的调用,并用其他内容替换递归.然后你可以调用query.Run(运行标准IQueryable实现).

虽然正如我所说,这可能很难实现 - 但也许,如果你有一些你可以轻松处理的特定类型的递归,它可能是一个选择.但是,如果LINQ to SQL没有为任何标准模式生成公用表表达式,那么我认为你不能训练它来生成它们 - 据我所知,翻译器实际上并不是可扩展的.