Les pièges de frappe
Cette courte page donne une description intuitive de quelques problèmes courants rencontrés par les novices lors de l'utilisation du système de types de Haskell.
Polymorphisme lié à Let
Tout langage utilisant le système de types Hindley-Milner présente ce que l'on appelle un polymorphisme lié à Let, car les identificateurs non liés à l'aide d'une clause let ou where (ou au niveau supérieur d'un module) sont limités par rapport à leur polymorphisme. En particulier, une fonction liée à lambda (c'est-à-dire une fonction passée en argument à une autre fonction) ne peut pas être instanciée de deux manières différentes. Par exemple, ce programme est illégal :
- let f g = (g [], g 'a') -- expression mal typée
- in f (\x->x)
car g, lié à une abstraction lambda dont le type principal est a->a, est utilisé dans f de deux manières différentes : une fois avec le type [a]->[a], et une fois avec le type Char->Char.
Surcharge numérique
Il est parfois facile d'oublier que les nombres sont surchargés et non implicitement contraints aux différents types numériques, comme dans de nombreux autres langages. Les expressions numériques plus générales ne peuvent parfois pas être aussi génériques. Une erreur de frappe numérique courante ressemble à ceci :
- average xs = sum xs / length xs -- Mauvais !
(/) nécessite des arguments fractionnaires, mais le résultat de length est un Int. L'incompatibilité de type doit être corrigée avec une contrainte explicite :
- average :: (Fractional a) => [a] -> a
- average xs = sum xs / fromIntegral (length xs)
La restriction du monomorphisme
Le système de types Haskell contient une restriction liée aux classes de types ne se trouvant pas dans les systèmes de types Hindley-Milner ordinaires : la restriction du monomorphisme. La raison de cette restriction est liée à une ambiguïté subtile de type et est expliquée en détail dans le rapport. Une explication plus simple suit :
La restriction du monomorphisme stipule que tout identifiant lié par une liaison de motif (incluant les liaisons à un identifiant unique), et n'ayant pas de signature de type explicite, doit être monomorphe. Un identificateur est monomorphe s'il n'est pas surchargé, ou s'il est surchargé mais est utilisé dans au plus une surcharge spécifique et n'est pas exporté.
Les violations de cette restriction entraînent une erreur de type statique. Le moyen le plus simple d'éviter le problème est de fournir une signature de type explicite. Notez que n'importe quelle signature de type fera l'affaire (à condition qu'elle soit de type correct).
Une violation courante de la restriction se produit avec des fonctions définies de manière d'ordre supérieur, comme dans cette définition de sum du Standard Prelude :
- sum = foldl (+) 0
En l'état, cela provoquerait une erreur de type statique. Nous pouvons résoudre le problème en ajoutant la signature de type :
- sum :: (Num a) => [a] -> a
Notez également que ce problème ne se serait pas posé si nous avions écrit :
- sum xs = foldl (+) 0 xs
car la restriction s'applique uniquement aux liaisons de modèles.