Typed Racket unterscheidet sich stark von Haskell. Typsysteme in Lisp und Scheme und tatsächlich Typsysteme in traditionell untypisierten Sprachökosystemen im Allgemeinen haben ein grundlegendes Ziel, das andere Typsysteme nicht haben - sie arbeiten mit vorhandenem untypisiertem Code zusammen . Typed Racket führte beispielsweise ganz neue Typisierungsregeln ein, um verschiedene Racket-Redewendungen zu berücksichtigen. Betrachten Sie diese Funktion:
(define (first some-list)
(if (empty? some-list)
#f
(car some-list)))
Bei nicht leeren Listen wird das erste Element zurückgegeben. Bei leeren Listen wird false zurückgegeben. Dies ist in untypisierten Sprachen üblich. Eine getippte Sprache würde einen Wrapper-Typ wie verwenden Maybe
oder im leeren Fall einen Fehler auslösen. Wenn wir dieser Funktion einen Typ hinzufügen möchten, welcher Typ sollte verwendet werden? Es ist nicht [a] -> a
(in Haskell-Notation), weil es false zurückgeben kann. Dies ist auch nicht [a] -> Either a Boolean
der Fall, da (1) im leeren Fall immer false zurückgegeben wird, kein beliebiger Boolescher Wert, und (2) ein Typ vom Typ Elemente einschließt Left
und falsch Right
einfügt und Sie das "entweder auspacken" müssen, um zum eigentlichen Element zu gelangen. Stattdessen gibt der Wert eine echte Vereinigung zurück- Es gibt keine Wrapping-Konstruktoren, es wird in einigen Fällen einfach ein Typ und in anderen Fällen ein anderer Typ zurückgegeben. In Typed Racket wird dies mit dem Union-Typ-Konstruktor dargestellt:
(: first (All (A) (-> (Listof A) (U A #f))))
(define (first some-list)
(if (empty? some-list)
#f
(car some-list)))
Der Typ (U A #f)
gibt an, dass die Funktion entweder ein Element der Liste oder false ohne Umbruchinstanz zurückgeben kann Either
. Der Typprüfer kann daraus schließen, dass some-list
es sich entweder um einen Typ (Pair A (Listof A))
oder um eine leere Liste handelt, und schließt daraus, dass in den beiden Zweigen der if-Anweisung bekannt ist, welche davon der Fall ist . Die Typprüfung weiß, dass (car some-list)
die Liste im Ausdruck den Typ haben muss , (Pair A (Listof A))
da die if-Bedingung dies sicherstellt. Dies wird als Vorkommenstypisierung bezeichnet und soll den Übergang von nicht typisiertem Code zu typisiertem Code erleichtern.
Das Problem ist die Migration. Es gibt eine Menge untypisierten Racket-Codes, und Typed Racket kann Sie nicht einfach dazu zwingen, alle Ihre bevorzugten untypisierten Bibliotheken aufzugeben und einen Monat damit zu verbringen, Ihrer Codebasis Typen hinzuzufügen, wenn Sie ihn verwenden möchten. Dieses Problem tritt immer dann auf, wenn Sie einer vorhandenen Codebasis schrittweise Typen hinzufügen. Eine JavaScript-Anwendung dieser Ideen finden Sie unter TypeScript und unter Beliebiger Typ.
Ein schrittweises Typsystem muss Werkzeuge für den Umgang mit gängigen untypisierten Redewendungen und die Interaktion mit vorhandenem untypisiertem Code bereitstellen. Andernfalls ist die Verwendung sehr schmerzhaft. Ein Beispiel für Clojure finden Sie unter "Warum wir Core.typed nicht mehr verwenden" .