Buscar..


Lista de comprensión básica

Haskell tiene listas de comprensión , que se parecen mucho a las comprensiones de conjunto en matemáticas e implementaciones similares en lenguajes imperativos como Python y JavaScript. En su forma más básica, las listas de comprensión toman la siguiente forma.

[ x | x <- someList ]

Por ejemplo

[ x | x <- [1..4] ]    -- [1,2,3,4]

Las funciones también se pueden aplicar directamente a x:

[ f x | x <- someList ]

Esto es equivalente a:

map f someList

Ejemplo:

[ x+1 | x <- [1..4]]    -- [2,3,4,5]

Patrones en Expresiones de Generador

Sin embargo, x en la expresión del generador no es solo variable, sino que puede ser cualquier patrón. En casos de desajuste de patrón, el elemento generado se omite y el procesamiento de la lista continúa con el siguiente elemento, actuando así como un filtro:

[x | Just x <- [Just 1, Nothing, Just 3]]     -- [1, 3]

Un generador con una variable x en su patrón crea un nuevo alcance que contiene todas las expresiones a su derecha, donde x se define como el elemento generado.

Esto significa que los guardias pueden codificarse como

[ x | x <- [1..4], even x] ==
[ x | x <- [1..4], () <- [() | even x]] ==
[ x | x <- [1..4], () <- if even x then [()] else []]

Guardias

Otra característica de las listas de comprensión son los guardias, que también actúan como filtros. Los guardias son expresiones booleanas y aparecen en el lado derecho de la barra en una lista de comprensión.

Su uso más básico es

[x    | p x]   ===   if p x then [x] else []

Cualquier variable utilizada en una guarda debe aparecer a su izquierda en la comprensión, o estar dentro del alcance. Asi que,

[ f x | x <- list, pred1 x y, pred2 x]     -- `y` must be defined in outer scope

que es equivalente a

map f (filter pred2 (filter (\x -> pred1 x y) list))          -- or,

-- ($ list) (filter (`pred1` y) >>> filter pred2 >>> map f)     

-- list >>= (\x-> [x | pred1 x y]) >>= (\x-> [x | pred2 x]) >>= (\x -> [f x])

(el operador >>= es infixl 1 , es decir, se asocia (está entre paréntesis) a la izquierda). Ejemplos:

[ x       | x <- [1..4], even x]           -- [2,4]

[ x^2 + 1 | x <- [1..100], even x ]        -- map (\x -> x^2 + 1) (filter even [1..100])

Generadores anidados

Las comprensiones de listas también pueden dibujar elementos de varias listas, en cuyo caso el resultado será la lista de todas las combinaciones posibles de los dos elementos, como si las dos listas se procesaran de forma anidada . Por ejemplo,

[ (a,b) | a <- [1,2,3], b <- ['a','b'] ]

-- [(1,'a'), (1,'b'), (2,'a'), (2,'b'), (3,'a'), (3,'b')]

Comprensiones paralelas

Con la extensión de lenguaje Parallel List Comprehensions ,

[(x,y) | x <- xs | y <- ys]

es equivalente a

zip xs ys

Ejemplo:

[(x,y) | x <- [1,2,3] | y <- [10,20]] 

-- [(1,10),(2,20)]

Fijaciones locales

Las comprensiones de listas pueden introducir enlaces locales para las variables que contienen algunos valores provisionales:

[(x,y) | x <- [1..4], let y=x*x+1, even y]    -- [(1,2),(3,10)]

El mismo efecto se puede lograr con un truco,

[(x,y) | x <- [1..4], y <- [x*x+1], even y]   -- [(1,2),(3,10)]

Las comprensiones de let in list son recursivas, como siempre. Pero los enlaces del generador no lo son, lo que permite el sombreado :

[x | x <- [1..4], x <- [x*x+1], even x]       -- [2,10]

Hacer notación

Cualquier lista de comprensión puede ser codificado de manera correspondiente con la lista mónada de do la notación .

[f x | x <- xs]                 f  <$> xs         do { x <- xs ; return (f x) }

[f x | f <- fs, x <- xs]        fs <*> xs         do { f <- fs ; x <- xs ; return (f x) }

[y   | x <- xs, y <- f x]       f  =<< xs         do { x <- xs ; y <- f x ; return y }

Los guardias se pueden manejar usando Control.Monad.guard :

[x   | x <- xs, even x]                           do { x <- xs ; guard (even x) ; return x }


Modified text is an extract of the original Stack Overflow Documentation
Licenciado bajo CC BY-SA 3.0
No afiliado a Stack Overflow