将变量嵌入 F# 引用中

发布于 2024-09-08 20:11:57 字数 845 浏览 8 评论 0原文

我正在为 SQL 编写 F# dsl (http://github.com/kolosy/furious) 。

select 语句如下所示:

type person = {
    personId: string
    firstname: string
    lastname: string
    homeAddress: address
    workAddress: address
    altAddresses: address seq
}
and address = {
    addressId: string
    street1: string
    zip: string
}

let (neighbor: person seq) = 
    db.Yield <@ Seq.filter (fun p -> p.homeAddress.zip = '60614') @>

明显(且愚蠢)的问题是...我如何参数化报价?

如果我只是这样:

let z = "60614"
let (neighbor: person seq) = 
    db.Yield <@ Seq.filter (fun p -> p.homeAddress.zip = z) @>

那么 z 就会解析为静态属性访问器(PropertyGet(None, String z, []))。我需要一些东西来让我仅根据引用检索变量/let 绑定的值。有想法吗?

I'm writing an F# dsl for SQL (http://github.com/kolosy/furious).

A select statement would look like this:

type person = {
    personId: string
    firstname: string
    lastname: string
    homeAddress: address
    workAddress: address
    altAddresses: address seq
}
and address = {
    addressId: string
    street1: string
    zip: string
}

let (neighbor: person seq) = 
    db.Yield <@ Seq.filter (fun p -> p.homeAddress.zip = '60614') @>

The obvious (and silly) question is... How do I parametrize the quotation?

If I just somehting like:

let z = "60614"
let (neighbor: person seq) = 
    db.Yield <@ Seq.filter (fun p -> p.homeAddress.zip = z) @>

then z gets resolved into a static property accessor (PropertyGet(None, String z, [])). I need something that will let me retrieve the value of the variable/let binding based solely on the quotation. Ideas?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

空宴 2024-09-15 20:11:57

引号不是我的强项,但请查看此处的差异:

let z = "60614" 
let foo = <@ List.filter (fun s -> s = z) @> 
printfn "%A" foo

let foo2 = 
    let z = z
    <@ List.filter (fun s -> s = z) @> 
printfn "%A" foo2

我认为“z”对于表达式来说可能是本地的意味着捕获了值,而不是属性引用。

Quotations are not my forte, but check out the difference here:

let z = "60614" 
let foo = <@ List.filter (fun s -> s = z) @> 
printfn "%A" foo

let foo2 = 
    let z = z
    <@ List.filter (fun s -> s = z) @> 
printfn "%A" foo2

I think maybe having 'z' be local to the expression means the value is captured, rather than a property reference.

左秋 2024-09-15 20:11:57

除了 Brian 所写的之外 - 我相信访问全局 let 绑定值的编码也非常稳定,并且它们很可能会继续在中被编码为 PropGet未来。

这意味着您可以在翻译器中明确支持这种情况,并添加一个简单的预处理步骤来获取这些属性的值。这可以使用 ExprShape 来完成(它允许您仅使用 4 个案例来完全遍历报价)。这将使您的 DSL 也支持一般情况。

以下函数遍历引用并用其值替换对全局 let 的访问:

open Microsoft.FSharp.Quotations

let rec expand e = 
  match e with
  // Extract value of global 'let' bound symbols
  | Patterns.PropertyGet(None, pi, []) -> 
      Expr.Value(pi.GetValue(null, [| |]), e.Type)
  // standard recursive processing of quotations
  | ExprShape.ShapeCombination(a, b) -> 
      ExprShape.RebuildShapeCombination(a, b |> List.map expand)
  | ExprShape.ShapeLambda(v, b) -> Expr.Lambda(v, expand b)
  | ExprShape.ShapeVar(v) -> Expr.Var(v)

然后您可以编写以下代码来获取包含值而不是 PropGet 的引用:

let z = 5
let eOrig = <@ Seq.filter (fun p -> p = z) [ 1 .. 10 ]@> 
let eNice = expand eOrig

In addition to what Brian wrote - I believe that the encoding of access to global let bound values is also pretty stable and they will quite likely continue to be encoded as PropGet in the future.

This means that you could support this case explicitly in your translator and add a simple pre-processing step to get values of these properties. This can be done using ExprShape (which allows you to fully traverse quotation just using 4 cases). This would allow your DSL to support the general case as well.

The following function traverses quotation and replaces access to global lets with their value:

open Microsoft.FSharp.Quotations

let rec expand e = 
  match e with
  // Extract value of global 'let' bound symbols
  | Patterns.PropertyGet(None, pi, []) -> 
      Expr.Value(pi.GetValue(null, [| |]), e.Type)
  // standard recursive processing of quotations
  | ExprShape.ShapeCombination(a, b) -> 
      ExprShape.RebuildShapeCombination(a, b |> List.map expand)
  | ExprShape.ShapeLambda(v, b) -> Expr.Lambda(v, expand b)
  | ExprShape.ShapeVar(v) -> Expr.Var(v)

Then you can write the following to get a quotation that contains value instead of PropGet:

let z = 5
let eOrig = <@ Seq.filter (fun p -> p = z) [ 1 .. 10 ]@> 
let eNice = expand eOrig
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文