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

具有上述递归值的示例代码会产生以下 F# 编译器错误:

错误 FS0432:[<ReflectedDefinition>] 术语不能包含前缀拼接运算符“%”的使用

我在上面的代码中看不到任何切片运算符的用法,看起来像一个错误...... :)

看起来这是ReflectedDefinitionAttribute仅通过报价的问题,正常报价效果很好:

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

Lazy.create使用隐藏和Lazy.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# 编译器错误?

4

1 回答 1

5

我认为这可能是由 F# 中递归值的处理引起的。作为一种解决方法,您可以将递归引用转换为参数:

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

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

最后一行当然是无效的(就像您的原始代码一样),因为您正在创建一个立即递归引用,但它应该给您一个想法 - 实际上,您可能会包含x在一个 lambda 函数中。


编辑 最初,我认为问题可能如下,但我现在不确定(见评论)。

对我来说,它看起来更像是一个(可能已知的)限制,而不是一个意外的错误。您编写的代码的两个版本之间有一个重要区别 - 在第一种情况下,您绑定了一个名为的公共值(对 .NET 可见)x,而在第二种情况下,x它只是一个仅在引用中使用的符号。

必须存储在程序集元数据中的报价如下所示:

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

正文被引用了,但x不是引用符号,所以需要将它拼接到引用中(即会被求值,并在其位置使用结果)。请注意,此代码将失败,因为您正在声明一个具有立即引用的递归值 -x需要作为其定义的一部分进行评估,因此这将不起作用。

但是,我认为这%不能出现在ReflectedDefinition引号中(也就是说,您不能将上述内容存储在元数据中),因为它涉及一些运行时方面 - 您需要x在加载元数据时进行评估。

于 2010-05-30T15:39:55.763 回答