coldwa.st
Todas las guíasProgramaciónWebDatosHerramientasBases de datosHaskellConceptosCabal y buildsToolchainCompiladorRendimientoEditor y HLS

Haskell · sintaxis · listas

Las listas por comprensión de Haskell, explicadas

Por ColdwastActualizado el 14 de junio de 20266 min de lectura#haskell#lists#syntax
Código fuente en un editor de terminal
Las listas por comprensión construyen una nueva lista a partir de listas existentes, en una única expresión legible.

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)

Líneas de código fuente en una pantalla oscura
Líneas de código en una pantalla — una guarda conserva solo los elementos que cumplen una condición.

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.

Guía independiente y mantenida por la comunidad. coldwa.st es un sitio de recursos de programación; este artículo es texto explicativo nuevo y original sobre las listas por comprensión de Haskell, no afiliado a los mantenedores del lenguaje. El código refleja el comportamiento estándar de Haskell/GHC — verifícalo con la documentación actual de GHC.