Вставить переменную внутри цитаты F # - PullRequest
4 голосов
/ 13 июля 2010

Я пишу F # DSL для SQL (http://github.com/kolosy/furious).

Оператор выбора будет выглядеть так:

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 привязки, основываясь исключительно на цитате. Идеи?

Ответы [ 2 ]

6 голосов
/ 13 июля 2010

Цитаты не являются моей сильной стороной, но обратите внимание на разницу здесь:

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' локально по отношению к выражению означает, что значение захватывается, а не ссылка на свойство.1004 *

4 голосов
/ 13 июля 2010

В дополнение к тому, что написал Брайан - я считаю, что кодирование доступа к глобальным let связанным значениям также довольно стабильно, и они, вполне вероятно, будут продолжать кодироваться как PropGet в будущем.

Это означает, что вы можете явно поддержать этот случай в вашем переводчике и добавить простой шаг предварительной обработки, чтобы получить значения этих свойств.Это можно сделать с помощью ExprShape (что позволяет полностью пересмотреть цитату, используя только 4 случая).Это позволит вашему DSL также поддерживать общий случай.

Следующая функция перебирает цитаты и заменяет доступ к глобальным 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
...