You are on page 1of 11

PLIEGUES

ESPECIALES

Haskell

Los pliegues (ofoldsen ingles). Son una


especie de funcin map, solo que reducen la
lista a un solo valor. Estos fueron creados para
encapsular
listas
vacas.
Anteriormente
debamos usar un patrnx:xsy hacamos
alguna operacin con un solo elemento de la
lista.

Un pliegue toma una funcin binaria, un valor inicial


y una lista que plegar.
La funcin binaria es llamada con el acumulador y el
primer (o ltimo) elemento y produce un nuevo
acumulador. Luego, la funcin binaria se vuelve a
llamar junto al nuevo acumulador y al nuevo primer (o
ltimo) elemento de la lista, y as sucesivamente.
sumaLista :: (Num a) => [a] ->
a
La funcin binaria toma dos parmetros por
si misma. Cuando se ha recorrido la lista
completa, solo permanece un acumulador,
que es el valor al que se ha reducido la
lista.
La funcin binaria toma dos parmetros por
si misma.

Vamos a analizar un poco este pliegue. \acc x -> acc


+ x es la funcin binaria donde suma sus parmetros.
0 es el valor inicial y xs es la lista que debe ser
plegada.
sumaLista1 :: (Num a) => [a] -> a
sumaLista1 xs = foldl (\acc x -> acc + x) 0 xs
podemos escribir esta implementacin de
forma ms bonita como:
sumaLista2 :: (Num a) => [a] -> a
sumaLista2 = foldl (+) 0
Tambin simplificando

sumaLista3 :: (Num a) => [a] -> a


sumaLista3 = foldl1 (+)

ghci> sum' [3,5,2,1]


11

Vamos a implementar otra funcin con un pliegue


por la izquierda antes de continuar con los pliegues
por la derecha.

elem' :: (Eq a) => a -> [a] -> Bool


elem' y ys = foldl (\acc x -> if x == y then True else acc) False ys
*Main> elem' 5 [5..50]
True
*Main> elem' 5 [8..50]
False

Ahora los pliegues por la derecha funcionan igual


que los pliegues por la izquierda, solo que el
acumulador consume elemento por la derecha.
La funcin binaria de los pliegues por la izquierda
como primer parmetro el acumulador y el valor
actual como segundo parmetro.
\acc x > ...

La funcin binaria de los pliegues por la derecha


tiene el valor actual como primer parmetro y el
acumulador despus.
\x acc > ...

Vamos a implementar la funcin map con un


pliegue por la derecha. El acumulador ser una lista,
en la que iremos acumulando los elemento de la
lista ya mapeados. Es obvio que el valor inicial ser
una lista vaca.
map' :: (a -> b) -> [a] -> [b]
map' f xs = foldr (\x acc -> f x : acc) [] xs

*Main> map' (+6) [1..20]

[7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26]

Si pones del revs una lista, puedes hacer un


pliegue por la derecha como si fuera un pliegue por
la izquierda y viceversa.

Una gran diferencia es que los pliegues por la


derecha funcionan con listas infinitas, mientras que
los pliegues por la izquierda no.

Los pliegues se pueden utilizar para implementar


cualquier funcin que recorra una lista, elemento a
elemento, y luego devuelvan un valor. Siempre que
quieras recorrer una lista y devolver un valor, hay
posibilidades de utilizar un pliegue.
Las funciones foldl1 y foldr1 son muy parecidas a
foldl y foldr, solo que no necesitas indicar un valor
de inicio.
maximum' :: (Ord a) => [a] -> a
maximum' = foldr1 (\x acc -> if x > acc then x else acc)

scanl y scanr son como foldl y foldr, solo que


devuelven todos los acumuladores intermedios en
forma de lista. Existen tambin scanl1 y scanr1, que
son similares a foldl1 y foldr1.
ghci> scanl (+) 0 [3,5,2,1]
[0,3,8,10,11]
ghci> scanr (+) 0 [3,5,2,1]
[11,8,3,1,0]

Cuando usamos scanl, el resultado final ser el


ltimo elemento de la lista resultante mientras que
con scanr estar al principio.