递归查询理解(F#3.0)

时间:2012-04-30 16:04:08

标签: f#

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

有什么想法吗?

1 个答案:

答案 0 :(得分:5)

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

我认为支持这一点非常困难。您可以为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方法中,您会获得代表查询的报价单。您可以预处理它并使用对标准MyQueryBuilder操作的调用替换对query的所有调用,并用其他内容替换递归。然后,您可以致电query.Run(运行标准IQueryable实施)。

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