Haskell a une notion de «fonctions génériques» qui a une certaine similitude apparente avec le lisp commun - n'ayant aucune expérience avec Haskell ni avec le lisp commun, je pourrais être très approximatif ici. Cela signifie que l'on peut définir une fonction générique to_string
pour définir une représentation sous forme de chaîne pour tous les types. Bien sûr, la facilité doit être définie dans les cas particuliers mais il existe une to_string
fonction dont la signature est α → string
.
Les types sont-ils effacés dans Haskell, comme dans OCaml? Si oui, en quoi l'implémentation des «fonctions génériques» dans Haskell diffère-t-elle de celle du lisp commun, où les types sont dynamiques, et donc pas effacés?
Je comprends que les détails de l'implémentation sont spécifiques au compilateur, mais il existe probablement des dispositions communes à de nombreuses ou à toutes les implémentations.
la source
a -> String
. Vous auriez plus probablement une contrainte de type, commeShow a => a -> String
.Réponses:
Jusqu'à présent, la réponse est trompeuse.
Il faut faire une distinction entre le polymorphisme "paramétrique" et "surcharge ad-hoc". Paramétrique signifie "se comporte uniformément pour tous les types a", tandis que "ad-hoc" - ce que Simon appelle polymorphe - modifie l'implémentation en fonction du type.
Des exemples des deux sont
reverse :: [a] -> [a]
, qui est paramétrique etshow :: Show a => a -> String
qui est "ad-hoc" surchargé.Si vous voulez plus d'une intuition abstraite, je pense que cela aide à considérer les classes de verbes en langage naturel qui "fonctionnent" pour tous les objets, comme "posséder" ou "penser" qui ne posent aucune contrainte à l'objet, mais " ouvrir "nécessite que ce dont nous parlons puisse être ouvert. Je peux «penser à une porte» et «ouvrir une porte», alors que cela n'a aucun sens, par exemple, «ouvrir un arbre». Pousser encore plus loin l'exemple «ouvrir» est «polymorphe ad hoc» car «ouvrir une fenêtre» et «ouvrir un ticket de réclamation auprès du service client» sont deux choses très différentes. Si cela semble forcé - oubliez-le! Ça marche pour moi.
Les deux sont cependant résolus au moment de la compilation et en fait "effacés". Modulo diverses extensions GHC et Template Haskell, etc. Les types sont en fait effacés au moment de la compilation et ne sont jamais inspectés au moment de l'exécution.
Les fonctions paramétriques polymorphes se comportent de manière identique pour tous les types, donc un seul morceau de code doit être généré, tandis que le compilateur décide au moment de la compilation quelle version d'une fonction "classée par type" doit être exécutée à un point de programme particulier. C'est aussi pourquoi la restriction d'une instance par type par classe de type et la solution de contournement "newtype" correspondante existent.
L'implémentation est détaillée dans le manuel SPJ et dans le document Wadler et Blotts sur les classes de types .
la source
forall
extension GHC ).avertissement: mes antécédents dans CS ne sont pas très solides, donc je ne pourrais pas toujours utiliser le vocabulaire correct, et je peux me tromper sur certains points. Quoi qu'il en soit, voici ma compréhension:
Je pense que vous confondez les génériques avec le polymorphisme.
Les types génériques tels que
List<Foo>
sont utilisés pour décrire les types qui prennent d'autres types en paramètre et permettent une vérification de type plus riche.Une fonction générique dans haskell pourrait être
count:: List a -> Int
. Il accepte des listes de tout type et renvoie le nombre d'éléments. Il n'y a qu'une seule implémentation.Habituellement, lors de la définition de List, vous ne pouvez rien supposer de T. Vous pouvez seulement le stocker et le rendre.
Votre
to_string
fonction est une fonction polymorphe, ce qui signifie qu'elle se comportera différemment selon les circonstances. Dans haskell, cela se fait avec des classes de types, qui fonctionnent comme des adjectifs pour les types.Vous avez une
Show
classe de types, qui définit uneshow :: a -> String
fonction.Lorsqu'un type
Foo
implémente laShow
classe de types, il doit fournir la définition deshow
. Ce type peut ensuite être utilisé dans des fonctions nécessitant leShow
qualificatif (comme dansShow a => a -> whatever
). Haskell ne peut pas effacer les types, car ces fonctions doivent trouver l'implémentation correcte de lashow
fonction.la source