4

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, []))に解決されます。引用のみに基づいて変数/レットバインディングの値を取得できるものが必要です。アイデア?

4

2 に答える 2

6

引用は私の得意ではありませんが、ここで違いを確認してください:

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'が式に対してローカルであるということは、プロパティ参照ではなく、値がキャプチャされることを意味すると思います。

于 2010-07-12T22:08:11.393 に答える
4

ブライアンが書いたことに加えて、グローバルバウンド値へのアクセスのエンコード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
于 2010-07-12T23:14:27.537 に答える