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.