Racket tipizzato è molto diverso da Haskell. Digitare i sistemi in Lisp e Scheme, e in effetti digitare i sistemi in ecosistemi linguistici tradizionalmente non tipizzati, hanno un obiettivo fondamentale che altri sistemi di tipi non - interoperano con il codice non tipizzato esistente . Ad esempio, Racket tipizzato ha introdotto nuove regole di digitazione per adattarsi a vari idiomi di Racket. Considera questa funzione:
(define (first some-list)
(if (empty? some-list)
#f
(car some-list)))
Per gli elenchi non vuoti, restituisce il primo elemento. Per gli elenchi vuoti, questo restituisce false. Questo è comune nelle lingue non tipizzate; un linguaggio tipizzato usa un tipo di wrapper come Maybe
o genera un errore nel caso vuoto. Se volessimo aggiungere un tipo a questa funzione, quale tipo dovrebbe essere usato? Non è [a] -> a
(nella notazione Haskell), perché può restituire false. Non è anche [a] -> Either a Boolean
, perché (1) restituisce sempre false nel caso vuoto, non un arbitrario booleano e (2) un tipo Entrambi avvolgere elementi in Left
e falso in Right
e richiede di "scartare il o "per arrivare all'elemento reale. Invece, il valore restituisce un vero unione - non esiste alcun costruttore di wrapping, restituisce semplicemente un tipo in alcuni casi e un altro tipo in altri casi. In Racket tipizzato, questo è rappresentato con il costruttore del tipo di unione:
(: first (All (A) (-> (Listof A) (U A #f))))
(define (first some-list)
(if (empty? some-list)
#f
(car some-list)))
Il tipo (U A #f)
afferma che la funzione potrebbe restituire un elemento della lista o falso senza alcuna istanza di wrapping Either
. Il type checker può inferire che some-list
è di tipo (Pair A (Listof A))
o la lista vuota, e inoltre deduce che nei due rami dell'istruzione if è noto quale di questi è il caso . Il controllo del tipo sa che nell'espressione (car some-list)
, l'elenco deve avere il tipo (Pair A (Listof A))
perché la condizione if lo garantisce. Questo è chiamato typing occorrenza ed è progettato per facilitare la transizione dal codice non tipizzato al codice digitato.
Il problema è la migrazione. C'è un sacco di codice Racket non incluso, e Typed Racket non può semplicemente costringerti ad abbandonare tutte le tue librerie non tipizzate preferite e passare un mese ad aggiungere tipi al tuo codebase se vuoi usarlo. Questo problema si applica ogni volta che il tuo tipo di aggiunta gradualmente a una base di codice esistente, vedi TypeScript e il suo Qualsiasi tipo per un'applicazione javascript di queste idee.
Un sistema di tipo graduale deve fornire strumenti per trattare gli idiomi comuni non tipizzati e interagire con il codice non ancora esistente. Usarlo sarà alquanto doloroso, vedi "Perché non usiamo più Core. digitato " per un esempio di Clojure.