3

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

有任何想法吗?

4

1 回答 1

5

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

我认为支持这一点将非常困难。您可以将自己的 F# 引用实现到 SQL 翻译器(这很难),或者您可以实现某种预处理器,该预处理器接受包含递归的 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 不为任何标准模式生成公用表表达式,那么我认为您不能训练它来生成它们——据我所知,翻译器并不是真正可扩展的。

于 2012-04-30T16:26:52.073 回答