Tres funciones que sustituyen casi todos los bucles
Map, filter y fold son tres funciones de Haskell que sustituyen casi todos los bucles sobre listas. Transforman cada elemento, se quedan con algunos o reducen la lista a un solo valor. Con ellas, "duplica cada precio, quédate con los caros y súmalos" cabe en una línea.
Verás cada una por separado y después las encadenarás.
Al final de esta lección
Nota
Puedo sustituir un bucle por map, filter o fold.
Palabras clave
| Palabra | Qué significa |
|---|---|
| Map | aplica una función a cada elemento de una lista |
| Filter | conserva los elementos que pasan una prueba |
| Fold | reduce una lista a un solo valor |
| Acumulador | el valor que va creciendo mientras se recorre la lista |
| Orden superior | una función que recibe otra función como dato |
Las celdas que rellenan los estudiantes quedan en blanco en esta vista previa.
Map aplica una función a cada elemento
Map recibe una función y una lista. Devuelve otra lista de la misma longitud, con la función aplicada a cada elemento.
map (* 2) [1, 2, 3] da [2, 4, 6]. Es una función de orden superior: recibe otra función como dato. La lista original no cambia nunca; map construye una nueva.
Dobla cada número de una lista
docker exec haskell ghc -e "map (*2) [1, 2, 3]"Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.
Cuenta las letras de cada palabra
docker exec haskell ghc -e "map length [\"pan\", \"leche\", \"huevos\"]"Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.
Pregunta el tipo de map
docker exec haskell ghc -e ":type map"Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.
Filter conserva lo que cumple una prueba
Filter recibe una prueba, una función que devuelve verdadero o falso, y una lista. Devuelve solo los elementos para los que la prueba es verdadera.
filter (> 10) [4, 12, 9, 15] da [12, 15]. La lista resultante puede ser más corta, o quedar vacía.
Quédate con los precios caros
docker exec haskell ghc -e "filter (> 10) [4, 12, 9, 15]"Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.
Quédate con los números pares
docker exec haskell ghc -e "filter even [1 .. 10]"Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.
Fold reduce una lista a un solo valor
Fold recorre la lista y va combinando sus elementos con un acumulador. Recibe una función de dos datos, el valor inicial y la lista.
foldr (+) 0 [1 .. 5] da 15. Hay dos versiones. foldl empieza por la izquierda y foldr por la derecha. Con la suma da igual, pero con la resta no.
Ejemplo: foldl (-) 10 [1, 2, 3]
| Elemento | Acumulador antes | Cuenta | Acumulador después |
|---|---|---|---|
| 1 | 10 | 10 - 1 | 9 |
| 2 | 9 | 9 - 2 | 7 |
| 3 | 7 | 7 - 3 | 4 |
| Fin | 4 | No quedan elementos | Resultado: 4 |
Las celdas que rellenan los estudiantes quedan en blanco en esta vista previa.
Suma los números del 1 al 5
docker exec haskell ghc -e "foldr (+) 0 [1 .. 5]"Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.
Resta empezando por la izquierda
docker exec haskell ghc -e "foldl (-) 10 [1, 2, 3]"Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.
La misma resta, por la derecha
docker exec haskell ghc -e "foldr (-) 10 [1, 2, 3]"Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.
Un error frecuente
Advertencia
Mucha gente cree que foldl y foldr dan siempre lo mismo. Con la suma sí, porque da igual el orden. Con la resta no: los dos Runs anteriores dan 4 y -8. Cuando el orden importa, mira siempre desde qué lado empieza el fold.
Encadena filter, map y suma
docker exec haskell ghc -e "sum (map (* 3) (filter even [1 .. 10]))"Se muestra aquí y no se ejecuta. Crea una cuenta gratuita para pulsar Ejecutar y escribirlo en el terminal de tu propio laboratorio.
Un bucle que hace las tres cosas
# Un bucle que hace tres cosas a la vez: filtrar, transformar y reducir.
prices = [4, 12, 9, 15]
total = 0
for price in prices:
if price > 10:
total = total + price * 2
print(total)
# En Haskell: sum (map (* 2) (filter (> 10) prices))
# Cambia el 10 por un 8 y vuelve a ejecutar.
Para ir más lejos
Con fold se puede construir casi cualquier función de listas. foldr (:) [] [1, 2, 3] devuelve la misma lista, y foldl (flip (:)) [] [1, 2, 3] la devuelve al revés.
Prueba a escribir con my_fold una función que dé la longitud de una lista y otra que dé el mayor de una lista de números.