La comprobación del tipo se puede hacer decidible enriqueciendo la sintaxis de forma apropiada. Por ejemplo, en el documento, tenemos lambdas escrito como \x -> e
; para marcar-verificar esto, debe suponer el tipo de x
. Sin embargo, con una sintaxis enriquecida adecuadamente, esto se puede escribir como \x :: t -> e
, lo que elimina las conjeturas del proceso. De manera similar, en el documento, permiten que las lambdas de nivel de tipo sean implícitas; es decir, si e :: t
, entonces también e :: forall a. t
. Para hacer la verificación de tipo, debe adivinar cuándo y cuántos forall
agregar y cuándo eliminarlos. Al igual que antes, se puede hacer esto más determinista mediante la adición de sintaxis: añadimos dos nuevos expresión forma /\a. e
y e [t]
y dos nueva regla de escritura que dice que si e :: t
, entonces /\a. e :: forall a. t
, y si e :: forall a. t
, entonces e [t'] :: t [t'/a]
(donde los corchetes en t [t'/a]
son soportes de sustitución) Luego, la sintaxis nos dice cuándo y cuántos foralls agregar, y cuándo eliminarlos también.
Entonces la pregunta es: ¿podemos pasar de Haskell a los términos del Sistema F suficientemente anotados? Y la respuesta es sí, gracias a algunas restricciones críticas impuestas por el sistema de tipo Haskell. El más crítico es que todos los tipos son de rango uno *. Sin entrar en demasiados detalles, el "rango" está relacionado con la cantidad de veces que tiene que ir a la izquierda de un constructor ->
para encontrar un forall
.
Int -> Bool -- rank 0?
forall a. (a -> a) -- rank 1
(forall a. a -> a) -> (forall a. a -> a) -- rank 2
En particular, esto restringe un poco el polimorfismo. No podemos escribir algo como esto con la fila uno tipos:
foo :: (forall a. a -> a) -> (String, Bool) -- a rank-2 type
foo polymorphicId = (polymorphicId "hey", polymorphicId True)
El siguiente restricción más importante es que las variables de tipo sólo pueden ser reemplazados por tipos monomorfas. (Esto incluye otras variables de tipo, como a
, pero no tipos polimórficos como forall a. a
). Esto asegura, en parte, que la sustitución de tipo preserva la jerarquía.
Resulta que si haces estas dos restricciones, entonces no sólo es de tipo inferencia decidible, pero también llegar mínimos tipos.
Si pasamos de Haskell a GHC, entonces podemos hablar no solo de lo que es tipable, sino de cómo se ve el algoritmo de inferencia. En particular, en GHC, hay extensiones que relajan las dos restricciones anteriores; ¿cómo hace GHC inferencia en ese entorno? Bueno, la respuesta es que simplemente ni siquiera lo intenta. Si desea escribir términos usando esas características, debe agregar las anotaciones de tipeo de las que hablamos desde el primer párrafo: debe anotar explícitamente dónde se introducen y eliminan forall
s. Entonces, ¿podemos escribir un término que rechaza el verificador de tipos de GHC? Sí, es fácil: simplemente use los tipos o impredicatividad de rango dos sin anotar. Por ejemplo, el siguiente no se escriba-cheque, aunque tiene un tipo de anotación explícita y es tipificable con rango de dos tipos:-
{-# LANGUAGE Rank2Types #-}
foo :: (String, Bool)
foo = (\f -> (f "hey", f True)) id
* En realidad, la restricción para clasificar dos es suficiente para que sea decidible, pero el algoritmo para los tipos de rango uno puede ser más eficiente. Los tipos de rango tres ya le dan al programador suficiente cuerda para que el problema de inferencia sea indecidible. No estoy seguro de si se conocían estos hechos en el momento en que el comité decidió restringir a Haskell a un rango de uno.
Haskell utiliza un resitricted * * edición del Sistema F se llama [* Hindley Milner *] [http://en.wikipedia.org/wiki/Hindley-Milner]. AFAIK es posible deducir el tipo de cualquier expresión que tenga un tipo. Hacer imposibles las verificaciones de tipos es cuestión de activar suficientes extensiones extrañas. – fuz
@FUZxxl: creo que habilitando solo 'RankNTypes' y' ImpredicativeTypes' uno tendría toda la potencia del Sistema F (y algo más, ya que Haskell también admite la abstracción sobre los operadores de tipo). –
Eso es lo que intenté decir con "Hacer que las verificaciones de tipos sean imposibles es cuestión de activar suficientes extensiones extrañas". – fuz