A raquete digitada é muito diferente de Haskell. Os sistemas de tipos no Lisp e Scheme, e de fato sistemas de sistemas em linguagens tradicionalmente não tipadas em geral, têm uma meta fundamental que outros sistemas de tipos não possuem - interoperando com o código não tipificado existente . A raquete digitada, por exemplo, introduziu novas regras de digitação para acomodar vários idiomas da raquete. Considere esta função:
(define (first some-list)
(if (empty? some-list)
#f
(car some-list)))
Para listas não vazias, isso retorna o primeiro elemento. Para listas vazias, isso retorna false. Isso é comum em idiomas sem tipo; um idioma digitado usaria algum tipo de invólucro como Maybe
ou geraria um erro no caso vazio. Se quisermos adicionar um tipo a essa função, que tipo deve ser usado? Não é [a] -> a
(na notação Haskell), porque pode retornar falso. Também não é [a] -> Either a Boolean
, porque (1) sempre retorna false no caso vazio, não é um booleano arbitrário e (2) um dos dois tipos envolve elementos Left
e false dentro Right
e exige que você "desembrulhe os dois" para chegar ao elemento real. Em vez disso, o valor retorna uma verdadeira união- não há construtores de quebra automática, ele simplesmente retorna um tipo em alguns casos e outro tipo em outros casos. No raquete digitado, isso é representado com o construtor de tipo de união:
(: first (All (A) (-> (Listof A) (U A #f))))
(define (first some-list)
(if (empty? some-list)
#f
(car some-list)))
O tipo (U A #f)
afirma que a função pode retornar um elemento da lista ou false sem nenhuma Either
instância de quebra automática. O verificador de tipos pode inferir que some-list
é do tipo (Pair A (Listof A))
ou da lista vazia e, além disso, infere que, nos dois ramos da instrução if , é conhecido qual deles é o caso . O verificador de tipos sabe que na (car some-list)
expressão, a lista deve ter o tipo (Pair A (Listof A))
porque a condição if garante isso. Isso é chamado digitação de ocorrência e foi projetado para facilitar a transição do código não digitado para o código digitado.
O problema é a migração. Existe uma tonelada de código de raquete não digitado por aí, e o Typed Racket não pode apenas forçá-lo a abandonar todas as suas bibliotecas não tipificadas favoritas e passar um mês adicionando tipos à sua base de código, se você quiser usá-la. Esse problema se aplica sempre que você adiciona tipos gradualmente a uma base de código existente, consulte TypeScript e seu tipo Qualquer para um aplicativo javascript dessas idéias.
Um sistema de tipo gradual deve fornecer ferramentas para lidar com idiomas comuns não digitados e interagir com o código não digitado existente. Caso contrário, será bastante doloroso. Consulte "Por que não estamos mais usando o Core.typed" para um exemplo do Clojure.