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

L'exemple de code avec la valeur récursive produit le document suivant F erreur # compilateur:Est-ce un bug des citations F #?

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

Je ne vois pas l'utilisation de l'opérateur de découpage en tranches dans le code ci-dessus, ressemble à un bug ... :)

On dirait que c'est le problème avec la citation par ReflectedDefinitionAttribute seulement, fonctionne bien normale cotation:

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

produit résultat attendu avec les cachés Lazy.create et Lazy.force usages:

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

La question est donc: est-ce un bug F # compilateur ou non?

Répondre

5

Je pense que cela peut être causé par le traitement des valeurs récursives dans F #. Pour contourner ce problème, vous pouvez transformer la référence récursive en un paramètre:

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

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

La dernière ligne est bien sûr pas valide (comme votre code d'origine), parce que vous créez une référence récurrente immédiate, mais il devrait donner vous l'idée - en réalité, vous devez probablement inclure x dans une fonction lambda.


EDITA l'origine, je pensais que le problème peut être comme ci-dessous, mais je ne suis pas sûr maintenant (voir commentaires).

Il ressemble plus à une limitation (probablement connue) à moi qu'un bug inattendu. Il existe une différence importante entre les deux versions du code que vous avez écrites - dans le premier cas, vous liez une valeur publique (visible à .NET) nommée x alors que dans le second cas, x est juste un symbole utilisé uniquement dans le citation.

La citation qui devrait être stocké dans les méta-données de l'ensemble ressemblerait à ceci:

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

Le corps est cité, mais x est pas un symbole cité, il doit être épissée dans la citation (c'est-à-dire qu'elle sera évaluée et le résultat sera utilisé à sa place). Notez que ce code échouera, car vous déclarez une valeur récursive avec une référence immédiate - x doit être évalué dans le cadre de sa définition, cela ne fonctionnera donc pas.

Cependant, je pense que % ne peut pas apparaître dans ReflectedDefinition citations (qui est, vous ne pouvez pas stocker ci-dessus dans les méta-données), car il implique certains aspects d'exécution - vous auriez besoin d'évaluer x lors du chargement de la méta-données .

+0

Merci pour votre réponse, Tomas! Je ne suis pas d'accord avec vous lorsque j'écris la version '[<]' que les métadonnées devraient ressembler '<@ (fun() ->% x +" abc ")() @>'. Entre guillemets, le nom 'x' devrait être lié à la valeur publique .NET, et non à la tranche de devis! Si le comportement est comme vous le dites, le code comme ceci: '[] laissez rec f() = (fun() -> f() +" abc ")()' devrait produire la même expecption, mais ce n'est pas le cas. – ControlFlow

+0

@ControlFlow: Je pense que votre argument est logique. Peut-être que cela doit faire quelque chose avec des valeurs récursives qui sont généralement assez compliquées en F #. –

+0

Je pense aussi, la gestion des valeurs récursives est une tâche non triviale pour les langages avides comme F # ... Peut-être que le compilateur devrait simplement restreindre les utilisations [] comme ça. – ControlFlow