Beruflich Dokumente
Kultur Dokumente
Haskell
Paradigmas de Lenguajes de Programación
20 cuatrimestre 2007
1.1. Funciones
Una de las formas más interesantes de expresiones es la función, cuyo tipo
esta indicado por una flecha: a → b es el tipo de las funciones que reciben un
argumento de tipo a y devuelven un argumento de tipo b. Las funciones en
Haskell son expresiones como cualquier otra: pueden ser argumento de otras
funciones, devolverse como resultado, contenerse en estructuras de datos,
etc.
1
Las sintaxis principal para definir funciones es muy parecida a la notación
matemática: a través de ecuaciones. La aplicación de una función a un valor
f (x) se escribe f x. Por ejemplo, podemos definir la función sucesor de la
siguiente forma:
sucesor n = n + 1
es decir con una ecuación que indica que el sucesor de n es n + 1 para
cualquier n. Los operadores también son funciones, con notación infija.
En el mundo matemático la definición de una función no siempre se
corresponde con una única ecuación, sino que puede estar separada en casos:
signo : R →Z
−1 si x < 0
signo(x) = 0 si x = 0
1 si x > 0
acotarAUnDigito : Z →
Z
9 si n > 9
acotarAUnDigito(n) = −9 si n < −9
n en cualquier otro caso
2
acotarAUnDigito :: Integer → Integer
acotarAUnDigito n | n > 9 = 9
| n < -9 = -9
| n ≤ 9 && n ≥ -9 = n
Acá las tres condiciones de las guardas son disjuntas, pero la de la última
ecuación es un poco más complicada. Una opción podrı́a ser aprovechar el
orden de evaluación: la única forma de evaluar la última ecuación es que no
se cumpla ninguna de las condiciones anteriores, y si eso sucede, tenemos que
evaluarla para cualquier n. Podemos entonces reemplazar la última condición
por True, que en ese lugar de la definición, tiene el efecto “cualquier otro
caso” que buscamos:
acotarAUnDigito n | n > 9 = 9
| n < -9 = -9
| True = n
Haskell tiene predefinida la palabra otherwise como sinónimo de True
para una lectura más natural de la definición.
acotarAUnDigito n | n > 9 = 9
| n < -9 = -9
| otherwise = n
?
1.1.1. Recursión
Recordemos la definición (matemática) de la función factorial :
factorial : N → N
factorial (0) = 1
factorial (n) = n × factorial (n − 1) si n > 0
Podemos definir esta función en Haskell con una correspondencia directa:
factorial :: Integer → Integer
factorial 0 = 1
factorial n | n > 0 = n ∗ factorial (n-1)
Esta función es recursiva porque su evaluación (en ciertos argumentos)
involucra el llamado a la misma función que se esta definiendo. La recursión
es una herramienta poderosa y usada muy frecuentemente en los programas
en Haskell.
1.1.2. Currificación
También como en matemática, las funciones pueden tener más de un
argumento:
3
potencia : N × R → R
potencia(0, x) = 1
potencia(n, x) = x × potencia(n − 1, x) si n > 0
En Haskell, podemos usar tuplas para contener los argumentos necesa-
rios. En general, cuando una variable no aparece del lado derecho de una
ecuación, puede reemplazarse por un guión bajo (_).
potencia :: (Integer, Double) → Double
potencia (0, _) = 1
potencia (n, x) | n > 0 = x ∗ potencia (n - 1, x)
Otra forma de definirla es a través de la misma función currificada: una
función equivalente de un único argumento, que devuelve una función que
completa el trabajo:
potencia :: Integer → Double → Double
potencia 0 _ = 1
potencia n x | n > 0 = x ∗ potencia (n - 1) x
Acá, potencia es una función que recibe un entero n y devuelve la función
potencia n; esta función recibe a su vez un número x y devuelve el resultado
de elevar x a la n.
La currificación es una correspondencia entre las funciones del primer
estilo (argumentos en una tupla) y el segundo (argumentos yuxtapuestos).
Esta correspondencia siempre existe, y nos permite la definición de funciones
a través de la aplicación parcial. Se podrı́a definir por ejemplo:
cuadrado, cubo, potCuarta :: Double → Double
cuadrado = potencia 2
cubo = potencia 3
potCuarta = potencia 4
y luego usarlas para computar cuadrados, cubos, etc.
1.2. Listas
Otra familia de tipos predefinidos en el lenguaje es el de las listas: secuen-
cias ordenadas de elementos de un mismo tipo, con repeticiones. [Integer]
representa el tipo lista de enteros, [Bool] es una lista de booleanos, etc.
Las expresiones de tipo lista se construyen con [] (que representa la lista
vacı́a) y : (a:as es la lista que empieza con el elemento a y sigue con la lista
as). También pueden escribirse entre corchetes, con los elementos separados
por comas:
[] :: [Bool]
[3] :: [Integer]
’a’ : (’b’ : (’c’ : [])) :: [Char]
[2 > 0, False, ’a’ == ’b’] :: [Bool]
[[], [1], [1,2]] :: [[Integer]]
4
El tipo String es sinónimo de [Char], y las listas de este tipo se pueden
escribir entre comillas: "plp" es lo mismo que [’p’, ’l’, ’p’].
5
fst :: (a, b) → a
fst (x, y) = x
Referencias
[1] Página de Haskell
www.haskell.org