[<ReflectedDefinition>]
let rec x = (fun() -> x + "abc") ()
上面带有递归值的示例代码会产生以下F#编译器错误:
错误FS0432:[&lt; ReflectedDefinition&gt;]术语不能包含前缀拼接运算符'%'的使用
我在上面的代码中看不到任何切片运算符用法,看起来像一个bug ... :)
看起来这只是通过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#编译器错误?
答案 0 :(得分: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
。