2010-05-30 55 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