Entendemos por inferencia de tipos la capacidad que tienen algunos lenguajes con chequeo estático de tipos para calcular el tipo de una expresión, función o variable sin necesidad de contar con anotaciones de tipo como sí se necesitan en C y Java por ejemplo.
La clave de este proceso es la regla por la cual se obtiene el tipo de la aplicación de una función:
f :: AB -> e :: A
-------------------
f e :: B
En términos más mundanos, lo que la regla dice es:
f
es una función cuyo dominio es A e imagen es B y,e
es una expresión de tipo Af e
(usamos a e
como argumento de f
) es BEjemplo, el tipo de not False
se puede inferir con esta regla:
not
es una función cuyo dominio es Bool e imagen es Bool y,False
es una expresión de tipo Boolnot False
es BoolOtro ejemplo, si queremos saber de que tipo es la expresión not 3
vemos que no tiene un tipo siguiendo la regla que especificamos anteriormente, porque requeriría que 3
sea de tipo Bool pero 3
no es un booleano.
Expresiones como not 3
, 2 + True
, length (4,3)
, fst [1,2]
, etc. no tienen un tipo y por lo tanto no son expresiones válidas en Haskell. Analicemos el siguiente caso:
funcionLoca x
| x > 0 = 1
| otherwise = True
Como por una rama retornamos un Int (1 :: Int) y por la otra retornamos un Bool (True :: Bool) no se puede obtener la imagen de la función funcionLoca, ergo la funcionLoca no se puede escribir en Haskell porque no tiene un tipo.
Sin embargo, que una expresión tenga tipo no significa que sea una expresión libre de errores.
head :: [ a ] -> a
head [] :: a
Pero a pesar de esto, si evaluamos la expresión
> head []
Error
Como la inferencia de tipos es un proceso ANTERIOR a la evaluación, los programas que hacemos en Haskell son Type Safe
Sí, es un concepto que fue desarrollado primero en el contexto del paradigma funcional e históricamente se lo ha encontraro principalmente asociado a lenguajes funcionales; sin embargo la idea de inferencia no está limitada este tipo de lenguajes y cada vez más está siendo utilizada en todo tipo de lenguajes.
Algunos lenguajes que poseen formas de inferencia de tipos son: Ada, BitC, Boo, C# 3.0, Cayenne, Clean, Cobra, D, Delphi, Epigram, F#, Haskell, haXe, JavaFX Script, ML, Mythryl, Nemerle, OCaml, Oxygene, Scala.
Por otro lado, la inferencia es más simple en los lenguajes que no permiten realizar asignaciones; y eso hace que sea más fácil de implementar en los lenguajes declarativos puros como Haskell.
Ver Cálculo del tipo de una función en Haskell
Recuerden que en Haskell ustedes pueden obtener el tipo de cualquier expresión escribiendo :t (type) en el interprete
> :t not
not :: Bool -> Bool
> :t not False
not False :: Bool
> :t not 3
Error
Si bien Haskell puede inferir correctamente el tipo de las funciones que definimos casi siempre, existen casos en los cuales necesita un poco de ayuda de parte del programador. En caso de que eso pase, conviene explicitar el tipo de nuestra función además de su definición en el .hs.
Por ejemplo, si estamos haciendo una función f que recibe una lista de a y retorna una lista de a, podemos hacer:
f :: [a] -> [a]
f lista = <lo que sea que hay que hacer con la lista para retornar otra>