Это ошибка цитат F #? - PullRequest
5 голосов
/ 30 мая 2010
[<ReflectedDefinition>]
let rec x = (fun() -> x + "abc") ()

Пример кода с рекурсивным значением выше приводит к следующей ошибке компилятора F #:

ошибка FS0432: [] термины не могут содержать использования префиксного оператора сращивания "%"

Я не вижу использования оператора нарезки в приведенном выше коде, похоже на ошибку ...:)

Похоже, что это проблема с цитатой только через 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 # или нет?

1 Ответ

5 голосов
/ 30 мая 2010

Я думаю, что это может быть вызвано обработкой рекурсивных значений в 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 цитатах (то есть вы не можете хранить вышеупомянутое в метаданных), потому что это включает в себя некоторые аспекты времени выполнения - вам нужно будет оценить x, когда загрузка метаданных.

...