2010-05-30 105 views
5
[<ReflectedDefinition>] 
let rec x = (fun() -> x + "abc")() 

與上面的遞歸值會產生以下F#編譯器錯誤示例代碼:這是一個F#語錄錯誤嗎?

error FS0432: [<ReflectedDefinition>] terms cannot contain uses of the prefix splice operator '%'

我看不到上面的代碼中的任何切片運算符的使用,看起來像一個bug ...... :)

看起來這是通過ReflectedDefinitionAttribute報價的問題只,正常報價行之有效:

let quotation = 
    <@ let rec x = (fun() -> x + "abc")() in x @> 

產生預期結果與隱藏Lazy.createLazy.force用法:

val quotation : Quotations.Expr<string> = 
    LetRecursive 
    ([(x, Lambda (unitVar, 
     Application 
     (Lambda (unitVar0, 
      Call (None, 
      String op_Addition[String,String,String](String, String), 
      [Call (None, 
       String Force[String](Lazy`1[System.String]), // ` 
       [x]), Value ("abc")])), 
     Value (<null>)))), 
    (x, Call (None, Lazy`1[String] Create[String](FSharpFunc`2[Unit,String]), [x])), 
    (x, Call (None, String Force[String](Lazy`1[String]), [x]))], x) // ` 

所以,問題是:這是一個F#編譯器錯誤或不?

回答

5

我想這可能是由F#中遞歸值的處理引起的。作爲一種變通方法,你可以把遞歸引用到一個參數:

[<ReflectedDefinition>] 
let foo x = (fun() -> x + "abc")() 

// To construct the recursive value, you'd write: 
let rec x = foo x 

最後一行是當然無效的(就像你的原碼)的,因爲你要創建一個即時遞歸引用,但它應該給你的想法 - 實際上,你可能會把x放在一個lambda函數中。


編輯本來,我以爲問題可能是下面的,但我現在不能確定(見註釋)。

它看起來更像是一個(可能已知)的限制,而不是一個意外的錯誤。你寫的代碼的兩個版本之間有一個重要的區別 - 在第一種情況下,你綁定了一個名爲x的公共值(對.NET可見),而在第二種情況下,x只是一個符號,只用於報價。

,將有被存儲在組件的元數據的報價是這樣的:

let rec x = <@ (fun() -> %x + "abc")() @> 

身體被引用,但x不帶引號的符號,所以它需要拼接成報價單(即將進行評估並將結果用於其位置)。請注意,此代碼將失敗,因爲您聲明遞歸值並立即引用 - x需要作爲其定義的一部分進行評估,因此這不起作用。

不過,我認爲%不能出現在ReflectedDefinition報價(即,你不能存儲在元數據上面的),因爲它涉及到一些運行方面 - 加載元數據時,你需要評估x

+0

謝謝你的回答,托馬斯! 我不同意你,當我寫''[]'版本元數據應該看起來像'<@ (fun() ->%x +「abc」)()@>'。在內部引用中,'x'名稱應該綁定到公共.NET值,而不是引用片段!如果它的行爲像你說的那樣,代碼就像這樣:'[]讓rec f()=(fun() - > f()+「abc」)()'也會產生相同的效果,但事實並非如此。 – ControlFlow 2010-05-30 16:06:39

+0

@ControlFlow:我認爲你的觀點是有道理的。也許這必須通過遞歸值來實現,這在F#中通常是非常複雜的事情。 – 2010-05-30 16:15:54

+0

我也這麼認爲,處理遞歸值對於像F#這樣渴望的語言來說是不平凡的任務......也許編譯器應該像這樣簡單地限制[]用法。 – ControlFlow 2010-05-30 16:29:11