Reflection 在F#引号中嵌入变量

Reflection 在F#引号中嵌入变量,reflection,f#,quotations,Reflection,F#,Quotations,我正在为SQL()编写一个F#dsl select语句如下所示: type person = { personId: string firstname: string lastname: string homeAddress: address workAddress: address altAddresses: address seq } and address = { addressId: string street1: stri

我正在为SQL()编写一个F#dsl

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') @>
type person={
人物:弦
名字:string
姓氏:string
家庭地址:地址
工作地址:地址
AltAddresss:地址序列
}
地址={
addressId:字符串
街道1:字符串
zip:字符串
}
let(邻居:人员序号)=
db.Yield p.homeAddress.zip='60614')@>
最明显(也是最愚蠢)的问题是。。。如何将报价参数化

如果我只是想:

let z = "60614"
let (neighbor: person seq) = 
    db.Yield <@ Seq.filter (fun p -> p.homeAddress.zip = z) @>
让z=“60614”
let(邻居:人员序号)=
db.Yield p.homeAddress.zip=z)@>

然后将
z
解析为静态属性访问器(
PropertyGet(None,String z,[])
)。我需要一个能够让我仅基于引号检索变量/let绑定值的东西。想法?

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

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=“60614”
设foo=s=z)@>
printfn“%A”foo
设foo2=
设z=z
s=z)@>
printfn“%A”foo2

我认为,可能表达式的“z”是局部的,这意味着值被捕获,而不是属性引用。

除了Brian所写的内容之外,我相信访问全局
let
绑定值的编码也相当稳定,并且它们很可能在将来继续编码为
PropGet

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

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

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
设z=5
设eOrig=p=z)[1..10]@>
设eNice=展开eOrig

哇。很好,谢谢。这会有多稳定?如中所示,这是一个未记录的特性,还是只是当前迭代的行为?我没有从引用的东西中得到很多温暖和模糊的东西。我相信这是一个稳定的特性;在顶层声明的名称是模块中的值(静态类的属性),而本地名称只是值。好的,所以这只是一个问题,因为我的测试工具是如何编写的。有道理。