[<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# или нет?
Я бы подумал, что это может быть вызвано обработкой рекурсивных значений в F #. В качестве обходного пути вы можете превратить рекурсивную ссылку в параметр:
[<ReflectedDefinition>]
let foo x = (fun() -> x + "abc") ()
// To construct the recursive value, you'd write:
let rec x = foo x
Последняя строка, конечно, недействительна (как и ваш исходный код), потому что вы создаете немедленную рекурсивную ссылку, но она должна дать вам идею - в действительности вы, вероятно, заключите x
в лямбда-функцию.
РЕДАКТИРОВАТЬ Первоначально я думал, что проблема может заключаться в следующем, но сейчас я не уверен (см. Комментарии).
Для меня это больше похоже на (вероятно, известное) ограничение, чем на неожиданную ошибку. Между двумя версиями написанного вами кода есть важное различие - в первом случае вы привязываете общедоступное значение (видимое для .NET) с именем x
, а во втором случае - x
- это просто символ, используемый только в цитате.
Цитата, которая должна быть сохранена в метаданных сборки, будет выглядеть так:
let rec x = <@ (fun() -> %x + "abc") () @>
Тело цитируется, но x
не является символом в кавычках, поэтому его необходимо быть включенным в цитату (то есть она будет оценена, а результат будет использован вместо нее). Обратите внимание, что этот код завершится ошибкой, потому что вы объявляете рекурсивное значение с непосредственной ссылкой - x
необходимо вычислить как часть его определения, поэтому это не сработает.
Однако я думаю, что %
не может появиться в цитатах ReflectedDefinition
(то есть вы не можете сохранить вышеуказанное в метаданных), потому что это связано с некоторыми аспектами выполнения - вы » d необходимо оценить x
при загрузке метаданных.