Comprendre l’erreur de type: «signature attendue Int * Int- Int mais Int * mais Int * Int- > Int»

StackOverflow https://stackoverflow.com/questions/324612

  •  11-07-2019
  •  | 
  •  

Question

Les commentaires sur les de poste sur Javascript côté serveur a commencé à discuter des avantages des systèmes de typage dans les langues. commentaire décrit:

  

... exemples de HM systèmes où vous pouvez obtenir des choses comme:

expected signature Int*Int->Int but got Int*Int->Int

Pouvez-vous donner un exemple d'une définition de fonction (ou deux?) et un appel de fonction qui produirait cette erreur? Cela semble être assez difficile à déboguer dans un programme volumineux.

Aussi, aurais-je pu voir une erreur similaire dans Miranda ? (Je ne l'ai pas utilisé depuis 15 ans et je ne m'en souviens plus très bien)

Était-ce utile?

La solution

Je prendrais l'avis de Yegge (et d'Ola Bini) sur le typage statique avec un grain de sel. Si vous appréciez ce que vous donne le typage statique, vous apprendrez comment fonctionne le système de typage du langage de programmation que vous choisissez.

IIRC, ML utilise la syntaxe '*' pour les n-uplets. < tapez > * < type > est un type de tuple avec deux éléments. Donc, (1, 2) aurait le type int * int.

Haskell et ML utilisent tous les deux - > pour les fonctions. En ML, int * int - > int serait le type d'une fonction qui prend un tuple d'int et d'int et le mappe sur un int.

Si vous essayez de passer des arguments entre parenthèses et virgules, comme ce serait le cas avec C ou Pascal, une des raisons pour lesquelles vous pourriez voir une erreur qui ressemble vaguement à celle que Ola a citée lorsqu’il arrive à ML une fonction qui prend deux paramètres.

Le problème, c’est que les langages fonctionnels modélisent généralement les fonctions de plusieurs paramètres en tant que fonctions renvoyant des fonctions; toutes les fonctions ne prennent qu'un seul argument. Si la fonction doit prendre deux arguments, elle prend un argument et renvoie une fonction d'un argument unique, qui renvoie le résultat final, etc. Pour rendre tout cela lisible, l’application des fonctions s’effectue simplement par conjonction (c’est-à-dire en plaçant les expressions les unes à côté des autres).

Ainsi, une fonction simple dans ML (note: j'utilise F # comme mon ML) pourrait ressembler un peu à:

let f x y = x + y;;

Il a le type:

val f : int -> int -> int

(Une fonction prenant un entier et renvoyant une fonction qui prend elle-même un entier et retourne un entier.)

Cependant, si vous l'appelez naïvement avec un tuple:

f(1, 2)

... vous obtiendrez une erreur, car vous avez passé un int * int à quelque chose qui l'attendait.

Je suppose que c'est le "problème". Ola essayait de lancer des critiques. Je ne pense pas que le problème soit aussi grave qu'il le pense; certes, c'est bien pire dans les modèles C ++.

Autres conseils

Il est possible que cela soit en référence à un compilateur mal écrit qui n'a pas réussi à insérer des parenthèses pour dissiper les ambiguïtés des messages d'erreur. Plus précisément, la fonction attend un tuple de int et renvoie un int , mais vous avez passé un tuple de int et une fonction de int. à int . Plus concrètement (en ML):

fun f g = g (1, 2);

f (42, fn x => x * 2)

Ceci produira une erreur de type similaire à celle-ci:

  

Type attendu int * int - > int , saisissez le type int * (int - > int)

Si les parenthèses sont omises, cette erreur peut être ambiguë ambiguë.

Il convient de noter que ce problème est loin d’être spécifique à Hindley-Milner. En fait, je ne peux penser à aucune erreur de type étrange, spécifique à H-M. Du moins, aucun ne ressemble à l'exemple donné. Je soupçonne qu'Ola soufflait juste de la fumée.

Etant donné que de nombreux langages fonctionnels vous permettent de relier les noms de types de la même manière, il est en fait assez facile de se retrouver avec une telle erreur, surtout si vous utilisez des noms quelque peu génériques pour vos types (par exemple, t ) dans différents modules. Voici un exemple simple dans OCaml:

# let f x = x + 1;;
val f : int -> int = <fun>
# type int = Foo of string;;
type int = Foo of string
# f (Foo "hello");;
This expression has type int but is here used with type int

Ce que j'ai fait ici est de relier l'identificateur de type int à un nouveau type incompatible avec le type int intégré. Avec un peu plus d'effort, nous pouvons obtenir plus ou moins la même erreur que ci-dessus:

# let f g x y = g(x,y) + x + y;;
val f : (int * int -> int) -> int -> int -> int = <fun>
# type int = Foo of int;;
type int = Foo of int
# let h (Foo a, Foo b) = (Foo a);;
val h : int * int -> int = <fun>
# f h;;
This expression has type int * int -> int but is here used with type
  int * int -> int
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top