Domanda

Sto scrivendo un f # dsl per sql ( http://github.com/kolosy/furious).

A Seleziona affermazione sarà simile a questo:

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') @>
.

La domanda ovvia (e sciocco) è ... come faccio parametrizzare la citazione?

Se ho solo un po 'come:

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

Allora z viene risolto in un accessorio di proprietà statico (PropertyGet(None, String z, [])).Ho bisogno di qualcosa che mi permetterà di recuperare il valore della variabile / lasciare il legame basato esclusivamente sulla citazione.Idee?

È stato utile?

Soluzione

Citazioni non sono il mio forte, ma controlla la differenza qui:

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
.

Penso che forse avere "z" essere locale all'espressione significa che il valore viene catturato, piuttosto che un riferimento di proprietà.

Altri suggerimenti

Oltre a ciò che Brian ha scritto - credo che la codifica dell'accesso ai valori globali generacoli di let sia anche piuttosto stabile e probabilmente continueranno a essere codificata come PropGet in futuro.

Ciò significa che è possibile supportare questo caso esplicitamente nel traduttore e aggiungere un semplice passo di pre-elaborazione per ottenere valori di queste proprietà.Questo può essere fatto usando ExprShape (che consente di trasformare completamente la quotazione utilizzando 4 casi).Ciò consentirebbe al tuo DSL di supportare anche il caso generale.

La seguente funzione attraversa la quotazione e sostituisce l'accesso a generatori globali con il loro valore:

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)
.

Quindi è possibile scrivere quanto segue per ottenere un preventivo che contiene valore anziché let:

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

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top