Haskell Hero

Haskell Hero es un manual interactivo del lenguaje Haskell para principiantes.

Tipos I

Tipos básicos


Tipos como cajas

Un tipo es una colección de valores relacionados.

En el modelo de cajas un tipo es una caja que contiene cajas de la misma forma.

  • Integer: todos los números enteros
  • Int: enteros pequeños (aproximadamente desde -500.000.000 hasta 500.000.000)
  • Bool: valores de verdad
  • Float: números decimales
  • Char: caracteres
  • String: cadenas de caracteres

Cuando queremos escribir que 1 es Integer, lo hacemos con dos dos puntos de manera siguiente. Esta notación se llama la anotación de tipo.

1 :: Integer
De esta manera lo podemos aplicar también a otros tipos:
'v'  :: Char
True :: Bool
5.0  :: Float

Haskell puede inferir el tipo de función por si solo pero si lo definimos para él, vamos a encontrar errores en nuestro código más rápido. Si por ejemplo queremos definir la función unaria multiplicadoCinco que multiplica su parámetro por cinco, podemos escribir:

multiplicadoCinco x = even x
y Hugs lo aceptaría sin quejas. Encontraríamos un problema solo cuando usaríamos la función por primera vez y descubriríamos que la función no devuelve Integer, sino Bool. Si usáramos la anotación de tipo,
multiplicadoCinco :: Integer -> Integer
multiplicadoCinco x = even x
encontraríamos el error ya cargando el script al intérprete.

Estructuras de datos

Tuplas

Tengamos por ejemplos tuplas (2,'a'), (105,'#') y (-9,'Q'). Podemos ver que estas duplas tienen como el primer elemento un número entero y como el segundo elemento un carácter. Podemos decir que todas las tres duplas son de tipo (Integer,Char). De misma manera escribiríamos el tipo de triplas, cuádruplas, ...

(True,7), (False,-1)                 :: (Bool,Integer)
("Juan",1.0,'w'), ("Juana",2.6,'&')  :: (String,Float,Char)
(5,(False,4)), (7,(False,-1))        :: (Integer,(Bool,Integer))
()                                   :: () -- la tupla de aridad 0/la tupla vacía

Listas

A diferencia de las tuplas, los elementos en el listo deben ser del mismo tipo. Por ejemplo [1,2,3,4,5] es una lista de números enteros, es decir, de tipo [Integer].

[True,False,False,True]    :: [Bool]
[5.0,6.105,10.89]          :: [Float]
[(5,'a'),(7,'W')]          :: [(Integer,Char)]
     -- una lista de duplas
[[1,2,5],[],[11,14,15,16]] :: [[Integer]]
     -- una lista de listas de números enteros
Una lista vacía con ninguna anotación de tipo es una lista cualquiera.
[] :: [a]

Un tipo especial de listas es una lista de caracteres [Char] que se escribe a menudo como una cadena String. Estos dos tipos son sustituibles a gusto de cada uno. [Char] se puede usar en un lugar donde esperamos String y podemos usar String en vez de una lista [Char].

String   ≡  [Char]
"Hola"   ≡  ['H','o','l','a']
"#&@?!"  ≡  ['#','&','@','?','!']

Tipos de funciones

La anotación de tipo de una función se hace de manera siguiente:

[función] :: tipo de primer parámetro -> tipo de segundo parámetro
            -> ... -> tipo de resultado

Ejemplo:

Definid una función mas2 con la anotación de tipo que toma dos números enteros como parámetros y devuelve su suma, también un número entero.


Una tal definición podría ser:

mas2     ::  Integer -> Integer -> Integer
mas2 x y  =  x + y

Tipos polimórficos

La función id toma un parámetro que devuelve sin cambios. Está definida de manera siguiente:

id x = x

¿Qué es su tipo? Si toma un número entero, devuelve un número entero.

id 5 ~> 5
Entonces su tipo podría ser id :: Integer -> Integer.

Si le asignásemos este tipo, limitaríamos su uso inútilmente. Después no podríamos por ejemplo aplicarla a una lista de cadenas.

id ["abc","DeQ","ASDF"]  ~>  ["abc","DeQ","ASDF"]
Además, nos gustaría que id trabajara también con funciones.
(id even) 5  ~>  even 5  ~>  False
En este caso debería tener el tipo
id :: (Integer -> Bool) -> Integer -> Bool

Por eso tenemos tipos polimórficos. Los escribimos con cadenas que empiezan con minúscula y generalmente su nombre consta de una sola minúscula del principio del alfabeto. Esta notación la llamamos una variable de tipo.

La función id es entonces de tipo id :: a -> a, lo que significa que puede tomar cualquier cosa y después devuelve un resultado del mismo tipo que el parámetro que ha tomado.