2 votes

Comprendre l'erreur d'inadéquation de type ?

Pourquoi cette déclaration me donne-t-elle une erreur de correspondance de type,

let x = List.rev [] in (3::x, true::x);; 

alors que cette déclaration ne le fait pas ?

let x = [] in (3::x, true::x);;

Je suppose que c'est parce que x reçoit un appel de fonction dans la première instruction, alors qu'il ne reçoit qu'une liste vide dans la deuxième instruction. Mais je ne sais pas exactement pourquoi la seconde fonctionne et pas la première ? Toute aide sera la bienvenue. Merci de votre aide.

3voto

rmunn Points 2576

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 :

  1. L'expression du côté droit de la let est un pur par exemple, il n'a pas d'effets secondaires, y
  2. 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).

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X