Haskell · sintaxis · listas
Las listas por comprensión de Haskell, explicadas
Una de las primeras cosas que hacen que Haskell se sienta elegante es la lista por comprensión: una forma concisa de construir una nueva lista a partir de otras existentes, que refleja la notación matemática de definición de conjuntos que quizá recuerdes del colegio. Esta guía explica la sintaxis, los generadores múltiples, las guardas y cómo se relacionan las comprensiones con map y filter.
La sintaxis básica
Una lista por comprensión tiene la forma [ output | generator, condition ]. Lee la barra como "tal que":
-- the squares of 1 to 10
squares = [x*x | x <- [1..10]]
-- [1,4,9,16,25,36,49,64,81,100] Aquí x <- [1..10] es un generador: extrae cada x de la lista [1..10], y la parte anterior a la barra, x*x, es la expresión de salida aplicada a cada elemento.
Añadir guardas (filtrado)
Una guarda es una condición booleana que conserva solo los elementos que la satisfacen:
-- even numbers from 1 to 20, doubled
result = [x*2 | x <- [1..20], even x]
-- [4,8,12,16,20,24,28,32,36,40] Puedes combinar varias guardas, separadas por comas; todas deben cumplirse para que se incluya un elemento.
Generadores múltiples
Con más de un generador, la comprensión itera sobre todas las combinaciones (como bucles anidados), en orden:
-- all pairs from two small lists
pairs = [(x, y) | x <- [1,2,3], y <- ['a','b']]
-- [(1,'a'),(1,'b'),(2,'a'),(2,'b'),(3,'a'),(3,'b')] El generador situado más a la derecha varía más rápido. También puedes hacer que un generador posterior dependa de uno anterior — por ejemplo, extrayendo y de [x..10].
Cómo se relacionan con map y filter
Una comprensión es esencialmente map y filter en una sola forma legible. Estas son equivalentes:
[x*2 | x <- xs, even x]
map (*2) (filter even xs) Usa la que se lea mejor en cada caso. Las comprensiones brillan cuando tienes varios generadores o varias guardas; map/filter se componen bien en canalizaciones libres de puntos. Como Haskell es perezoso, una comprensión sobre una lista infinita como [1..] solo calcula los elementos que realmente consumes.
Preguntas frecuentes
¿Qué es un generador en una lista por comprensión? La parte x <- xs: extrae cada valor de x de la lista xs para alimentar la expresión de salida.
¿Qué es una guarda? Una condición booleana (como even x) colocada después de una coma; solo se conservan los elementos para los que es verdadera.
¿Puedo usar varios generadores? Sí — la comprensión produce todas las combinaciones, con el generador situado más a la derecha variando más rápido, como bucles anidados.
¿Son las comprensiones solo map y filter? Conceptualmente sí para los casos simples; las comprensiones suelen ser más legibles con varios generadores o guardas, mientras que map/filter se componen bien en canalizaciones.
Para conocer el lenguaje que hay detrás de la sintaxis, consulta qué es Haskell; las comprensiones son una de las características que lo hacen conciso y expresivo.