La raquette typée est très différente de Haskell. Les systèmes de types en Lisp et Scheme, et en fait les systèmes de types dans les écosystèmes langagiers traditionnellement non typés en général, ont un objectif fondamental que les autres systèmes de types n'interagissent pas avec le code non typé existant . La raquette typée, par exemple, a introduit de toutes nouvelles règles de frappe pour s'adapter à divers idiomes de raquette. Considérez cette fonction:
(define (first some-list)
(if (empty? some-list)
#f
(car some-list)))
Pour les listes non vides, cela renvoie le premier élément. Pour les listes vides, cela renvoie false. Ceci est courant dans les langues non typées; un langage tapé utiliserait un type de wrapper comme Maybe
ou lancerait une erreur dans le cas vide. Si nous voulions ajouter un type à cette fonction, quel type utiliser? Ce n'est pas le cas [a] -> a
(en notation Haskell), car il peut retourner faux. Ce n'est pas non plus le cas [a] -> Either a Boolean
, car (1) il renvoie toujours false dans le cas vide, pas un booléen arbitraire et (2) un type Soit encapsule les éléments dans Left
et false Right
et vous oblige à "déballer l'un ou l'autre" pour accéder à l'élément réel. Au lieu de cela, la valeur renvoie une véritable union- il n'y a pas de constructeur enveloppant, il retourne simplement un type dans certains cas et un autre type dans d'autres cas. Dans Typed Racket, cela est représenté par le constructeur de type d'union:
(: first (All (A) (-> (Listof A) (U A #f))))
(define (first some-list)
(if (empty? some-list)
#f
(car some-list)))
Le type (U A #f)
indique que la fonction peut renvoyer un élément de la liste ou false sans aucune Either
occurrence d' habillage . Le vérificateur de type peut déduire qu'il some-list
s'agit du type (Pair A (Listof A))
ou de la liste vide, et en outre il déduit que dans les deux branches de l'instruction if, on sait lequel de ces cas est connu . Le vérificateur de type sait que dans l' (car some-list)
expression, la liste doit avoir le type (Pair A (Listof A))
car la condition if le garantit. Cela s'appelle le typage d'occurrence et est conçu pour faciliter la transition du code non typé au code typé.
Le problème est la migration. Il y a une tonne de code Racket non typé, et Typet Racket ne peut pas simplement vous forcer à abandonner toutes vos bibliothèques préférées non typées et à passer un mois à ajouter des types à votre base de code si vous souhaitez l'utiliser. Ce problème s'applique chaque fois que vous ajoutez progressivement des types à une base de code existante, voir TypeScript et son type Any pour une application javascript de ces idées.
Un système de type progressif doit fournir des outils pour gérer les idiomes non typés courants et interagir avec le code non typé existant. L'utiliser sera assez douloureux sinon, voir "Pourquoi nous n'utilisons plus Core.typed" pour un exemple de Clojure.