Ahora veo que Racket tiene tipos. A primera vista, parece ser casi idéntico a la escritura de Haskell. ¿Pero el CLOS de Lisp está cubriendo parte del espacio que cubren los tipos de Haskell? Crear un tipo de Haskell muy estricto y un objeto en cualquier lenguaje OO parece vagamente similar. Es solo que he bebido un poco del Haskell kool-aid y estoy totalmente paranoico de que si voy por el camino de Lisp, me fastidiarán debido a la escritura dinámica.
fuente
Object
o cualquiera que sea la raíz del árbol de tipos. Esto es menos expresiva, porque se ven privados de la opción de decir que ciertas variables sólo pueden contener ciertos valores.Typed Racket es muy diferente de Haskell. Los sistemas de tipos en Lisp y Scheme, y de hecho los sistemas de tipos en ecosistemas de lenguaje tradicionalmente sin tipo en general, tienen un objetivo fundamental que otros sistemas de tipo no tienen: interoperar con el código sin tipo existente . Typed Racket, por ejemplo, introdujo reglas de escritura completamente nuevas para acomodar varios modismos de Racket. Considere esta función:
Para listas no vacías, esto devuelve el primer elemento. Para listas vacías, esto devuelve falso. Esto es común en idiomas sin tipo; un lenguaje escrito usaría algún tipo de contenedor como
Maybe
o arrojaría un error en el caso vacío. Si quisiéramos agregar un tipo a esta función, ¿qué tipo debería usarse? No lo es[a] -> a
(en notación Haskell), porque puede devolver falso. Tampoco lo es[a] -> Either a Boolean
, porque (1) siempre devuelve falso en el caso vacío, no es un booleano arbitrario y (2) un tipo Cualquiera de los dos encapsularía los elementosLeft
y falsificaríaRight
y requeriría que "desenvolviera los dos" para llegar al elemento real. En cambio, el valor devuelve una unión verdadera- no hay constructores de envoltura, simplemente devuelve un tipo en algunos casos y otro tipo en otros casos. En Typed Racket, esto se representa con el constructor de tipo de unión:El tipo
(U A #f)
indica que la función podría devolver un elemento de la lista o falso sin ningunaEither
instancia de ajuste . El verificador de tipos puede inferir quesome-list
es de tipo(Pair A (Listof A))
o de la lista vacía, y además infiere que en las dos ramas de la declaración if se sabe cuál es el caso . El verificador de tipos sabe que en la(car some-list)
expresión, la lista debe tener el tipo(Pair A (Listof A))
porque la condición if lo garantiza. Esto se llama tipificación de ocurrencia y está diseñado para facilitar la transición del código sin tipo al código escrito.El problema es la migración. Hay una tonelada de código de Racket sin tipo, y Typed Racket no puede forzarlo a abandonar todas sus bibliotecas sin tipo favoritas y pasar un mes agregando tipos a su base de código si desea usarlo. Este problema se aplica cada vez que agrega tipos gradualmente a una base de código existente, vea TypeScript y su tipo Any para obtener una aplicación javascript de estas ideas.
Un sistema de tipo gradual debe proporcionar herramientas para tratar modismos comunes sin tipo e interactuar con el código sin tipo existente. Usarlo será bastante doloroso de lo contrario, consulte "Por qué ya no usamos Core.typed" para ver un ejemplo de Clojure.
fuente