En Haskell estamos acostumbrados a escribir funciones de terminos a terminos.
Esto son funciones que dado un valor de un tipo, retornan otro valor de algun tipo.
En este punto el conjunto de los tipos y el conjunto de los terminos son dos universos separados, ya que a nadie se le ocurriría escribir algo como Int + 6
. ¿O si?
f :: Int -> Int
f n = 2 * n
g :: [Char] -> Int
g [] = 0
g (x:xs) = 1 + g xs
h :: String -> Bool
h _ = True
Supongamos que queremos escribir una función que dado un tipo nos retorne otro tipo.
Por ejemplo una función que dados dos tipos a
y b
nos retorne el tipo tupla de esos dos: (a, b)
mkTuple a b = (a, b)
El problema se da en que si definimos la función mkTuple
como está arriba obtendremos una función de términos a término.
Esto significa que podremos utilizarla pasandole como parametros ‘valores’ de ciertos tipos
ghci> mkTuple 5 'c'
(5, 'c') :: (Int, Char)
Es más, si utilizamos la función mkTuple
con tipos como parámetros obtendremos un error Illegal term-level ...
el cual nos dice que estamos utilizando tipos en el universo de terminos.
Además nos genera una pregunta ¿Qué tipo tienen los tipos?
ghci> mkTuple Int Char
Illegal term-level ...
Por suerte Haskell nos ofrece una solución a este problema.
Podemos declarar una función de tipo a tipo de la siguiente manera.
En realidad estamos declarando un tipo donde su constructor es MkTuple
, pero podemos mirarlo como una función que dados los tipos a
y b
nos genera o retorna el tipo (a, b)
type MkTuple a b = (a, b)
f :: MkTuple Int Char -> Int
f (a, b) = a
Por lo tanto ya tenemos una manera de definir funciones de tipos a tipos en Haskell.