[英]F# quotations: variable may escape scope
我有這段代碼:
let rec h n z = if n = 0 then z
else <@ (fun x -> %(h (n - 1) <@ x + %z @>)) n @>
從http://www.cs.rice.edu/~taha/publications/journal/dspg04a.pdf中的MetaOcaml示例轉換而來
在本文中,解釋了上面的示例將使用參數3
和.<1>.
得出以下結果.<1>.
(以MetaOcaml表示法):
.<(fun x_1 -> (fun x_2 -> (fun x_3 -> x_3 + (x_2 + (x_1 + 1))) 1) 2) 3>.
如您所見, x
被x_1
, x_2
等替換,因為x
否則只會在最內層的fun
引用x
。
但是在F#中這是不允許的。 我收到編譯時錯誤:“變量'x'用引號引起來,但被用作拼接表達式的一部分。這是不允許的,因為它可能逃避其范圍。” 所以問題是:如何更改它,使其可以編譯並具有與MetaOcaml輸出相同的語義?
更新以評論:我使用PowerPack實際評估報價。 但是我認為這與它無關,因為錯誤發生在編譯時。 到目前為止,報價評估工作正常。 但是,我知道這可能不是最有效的實現。
更新為Tomas的答案:我真的不希望x
是全局的,也不希望逃避范圍。 但我要相當於
let rec h n z = if n = 0 then z
else (fun x -> (h (n - 1) (x + z))) n
報價。 您的答案為(h 3 <@ 1 @>).Eval() = 4
,其中上面的結果為h 3 1 = 7
。 在這里,我希望7
是答案。
F#引號語法不支持可能會逃避范圍的變量,因此您需要使用Expr
操作顯式構造樹。 這樣的事情應該可以解決問題:
open Microsoft.FSharp.Quotations
let rec h n (z:Expr<int>) =
if n = 0 then z
else
let v = new Var("x", typeof<int>)
let ve = Expr.Var(v)
Expr.Cast<int>
(Expr.Application( Expr.Lambda(v, h (n - 1) <@ %%ve + %z @>),
Expr.Value(n)))
但是,這是一個非常人為的示例(以演示MetaOCaml中的變量捕獲,F#中不提供此功能)。 它只是生成像(2 + (1 + ...))
表達式。 您可以通過編寫類似以下內容來獲得相同的結果:
let rec h n (z:Expr<int>) =
if n = 0 then z
else h (n - 1) <@ n + %z @>
甚至更好:
[ 1 .. 4 ] |> List.fold (fun st n -> <@ n + %st @>) <@ 0 @>
我也遇到了F#引號中的此限制,如果支持此功能會很好。 但是,我認為實際上這不是一個大問題,因為F#引號未用於分階段的元編程。 它們對於分析現有的F#代碼比生成代碼更有用。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.