2010-07-12 49 views
4

我正在爲SQL編寫一個F#dsl(http://github.com/kolosy/furious)。在F#引用中嵌入變量

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綁定的值。想法?

回答

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」是本地的表現手法值被捕獲,而不是一個屬性的參考。

+0

哇。整潔,謝謝。那將會如何穩定?如在中,是沒有記錄的特徵,還是僅僅是當前迭代的行爲?我沒有得到很多熱情和模糊的挖掘報價的東西。 – kolosy 2010-07-12 22:11:37

+1

我相信這是一個穩定的功能;在頂層聲明的名稱是模塊中的值(靜態類的屬性),而本地名稱只是值。 – Brian 2010-07-12 22:27:41

+0

d'oh。好吧,所以這只是因爲我的測試工具被編寫的問題。說得通。 – kolosy 2010-07-12 23:08:31

4

除了Brian寫的 - 我相信對全球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