Essayez ce qui suit :
let x = [] ;;
Résultat : val x : 'a list
. F# sait que x
est une liste de type encore inconnu. Si elle avait un contenu, son type serait connu. Cela fonctionne parfaitement bien.
Mais ce qui suit no travail :
let x = List.rev [] ;;
Résultat :
erreur FS0030 : Restriction de valeur. La valeur 'x' a été déduite comme ayant un type générique.
val x : '_a list
Définissez "x" comme un simple terme de données, faites-en une fonction avec des arguments explicites ou, si vous ne souhaitez pas qu'il soit générique, ajoutez une annotation de type.
L'erreur "value restriction" en F# peut être difficile à comprendre - pourquoi la []
autorisé lorsque List.rev []
n'est pas ? - mais cet article entre dans les détails. Essentiellement, F# peut toujours se sentir en sécurité en faisant fonctions générique, mais il ne peut se sentir en sécurité qu'en faisant valeurs générique si les deux conditions suivantes s'appliquent :
- L'expression du côté droit de la
let
est un pur par exemple, il n'a pas d'effets secondaires, y
- L'expression du côté droit de la
let
es immuable .
Lorsque l'expression est []
alors F# sait qu'il s'agit d'une valeur pure, immuable, et peut donc la rendre générique ( 'a list
). Mais lorsque l'expression est someFunction []
le compilateur F# ne sait pas ce qu'il faut faire. someFunction
va faire. Même si dans ce cas, nous savons que List.rev
fait partie de la bibliothèque standard et correspond à ces deux scénarios, le compilateur F# ne peut pas savoir que . Dans un langage complètement pur comme Haskell, la signature de type d'une fonction permet de savoir qu'elle est pure, mais F# est un langage plus pragmatique. F# adopte donc l'approche de la sécurité garantie et fait no faire le résultat de List.rev []
générique.
Par conséquent, lorsque vous écrivez let x = [] in (3::x, true::x)
le []
est une valeur Générique liste vide, de sorte qu'il peut devenir soit un int list
ou un bool list
au besoin. Mais lorsque vous écrivez let x = List.rev [] in (3::x, true::x)
F# ne peut pas faire List.rev []
générique. Il peut dire "Ceci est une liste d'un type que je ne connais pas encore", et attendre que le type devienne clair. Ensuite, la première expression d'un type spécifique qui utilise cette liste, dans le cas présent 3::x
Le type de cette liste sera "verrouillé". C'est à dire que F# ne peut pas considérer cette liste comme générique, donc maintenant il a compris que cette liste vide est une liste vide de int
s. Et ensuite, lorsque vous essayez d'ajouter un bool
à un vide int list
c'est une erreur.
Si vous inversez le tuple pour qu'il soit true::x, 3::x
alors l'erreur de type serait également "inversée" : elle s'attendrait à une bool list
et trouver un int list
.
Donc la version courte de cette réponse est : vous frappez la restriction de la valeur F# même si cela n'est pas immédiatement évident puisque l'erreur que vous avez reçue ne mentionne pas du tout la restriction de valeur.
Voir Comprendre les erreurs de restriction de valeur de F# pour une bonne discussion sur la restriction de valeur, y compris l'endroit le plus courant où vous la verrez normalement (fonctions partiellement appliquées).