2010-05-30 19 views
5
[<ReflectedDefinition>] 
let rec x = (fun() -> x + "abc")() 

El código de ejemplo con el valor recursiva anterior produce el siguiente error F # compilador:¿Es este un error de citas F #?

error FS0432: [<ReflectedDefinition>] terms cannot contain uses of the prefix splice operator '%'

no puedo ver cualquier uso del operador de rebanado en el código anterior, se ve como un bicho ... :)

Parece que este es el problema con la cita a través de ReflectedDefinitionAttribute única, cita normal, funciona bien:

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

produce resultado esperado con los ocultos Lazy.create y Lazy.force usos:

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) // ` 

Así que la pregunta es: ¿se trata de un error de compilador de C o no?

Respuesta

5

Creo que esto puede deberse al tratamiento de valores recursivos en F #. Como solución alternativa, puede activar la referencia recursiva en un parámetro:

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

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

La última línea es, por supuesto, no válido (al igual que su código original), porque va a crear una referencia recursiva inmediata, pero se debe dar usted la idea - en realidad, probablemente encierre x en una función lambda.


EDITAROriginalmente, pensé que el problema puede ser tan abajo, pero no estoy seguro de que ahora (ver comentarios).

Parece más una limitación (probablemente conocida) para mí que un error inesperado. Hay una diferencia importante entre las dos versiones del código que escribió: en el primer caso, está vinculando un valor público (visible para .NET) llamado x, mientras que en el segundo caso, x es solo un símbolo utilizado solo en cotización.

La cita que tendría que ser almacenada en los metadatos de la asamblea se vería así:

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

es citado cuerpo, pero x no es un símbolo citado, por lo que debe ser empalmado en la cita (es decir, se evaluará y el resultado se usará en su lugar). Tenga en cuenta que este código fallará, porque está declarando un valor recursivo con referencia inmediata: el x debe evaluarse como parte de su definición, por lo que esto no funcionará.

Sin embargo, creo que % no puede aparecer en ReflectedDefinition citas (es decir, no se puede almacenar lo anterior en meta-datos), porque se trata de algunos aspectos de tiempo de ejecución - que había necesidad de evaluar x al cargar los metadatos .

+0

¡Gracias por su respuesta, Tomas! No estoy de acuerdo con usted en que cuando estoy escribiendo la versión '[]' que metadata debe parecerse a '<@ (fun() ->% x +" abc ")() @>'. Dentro de la cita, el nombre 'x' debe estar vinculado al valor .NET público, ¡no a la porción de la cita! Si fuera un comportamiento como el que dices, el código como este: '[] let rec f() = (fun() -> f() +" abc ")()' debería producir la misma expectación también, pero no es así – ControlFlow

+0

@ControlFlow: creo que tu punto tiene sentido. Tal vez esto tiene que hacer algo con valores recursivos que generalmente son algo bastante complicado en F #. –

+0

Creo que también, el manejo de valores recursivos no es una tarea trivial para lenguajes ansiosos como F # ... Tal vez el compilador simplemente debería restringir los usos [] como este. – ControlFlow

Cuestiones relacionadas