Haskell Language
Elenco delle comprensioni
Ricerca…
Comprensioni di lista di base
Haskell ha una comprensione delle liste , che assomiglia molto alla comprensione dell'insieme in matematica e implementazioni simili in linguaggi imperativi come Python e JavaScript. Alla loro più elementare, le list comprehensions prendono la seguente forma.
[ x | x <- someList ]
Per esempio
[ x | x <- [1..4] ] -- [1,2,3,4]
Le funzioni possono essere applicate direttamente anche a x:
[ f x | x <- someList ]
Questo è equivalente a:
map f someList
Esempio:
[ x+1 | x <- [1..4]] -- [2,3,4,5]
Modelli nelle espressioni del generatore
Tuttavia, x
nell'espressione del generatore non è solo variabile, ma può essere qualsiasi modello. In caso di mancata corrispondenza del motivo, l'elemento generato viene saltato e l'elaborazione dell'elenco continua con l'elemento successivo, agendo quindi come un filtro:
[x | Just x <- [Just 1, Nothing, Just 3]] -- [1, 3]
Un generatore con una variabile x
nel suo modello crea un nuovo ambito contenente tutte le espressioni alla sua destra, dove x
è definito come l'elemento generato.
Ciò significa che le guardie possono essere codificate come
[ x | x <- [1..4], even x] ==
[ x | x <- [1..4], () <- [() | even x]] ==
[ x | x <- [1..4], () <- if even x then [()] else []]
guardie
Un'altra caratteristica delle list comprehensions sono le guardie, che fungono anche da filtri. Le guardie sono espressioni booleane e appaiono sul lato destro della barra in una lista di comprensione.
Il loro uso più basilare è
[x | p x] === if p x then [x] else []
Qualsiasi variabile utilizzata in una guardia deve apparire alla sua sinistra nella comprensione, o comunque essere nella portata. Così,
[ f x | x <- list, pred1 x y, pred2 x] -- `y` must be defined in outer scope
che è 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])
(l'operatore >>=
è infixl 1
, cioè associa (è tra parentesi) a sinistra). Esempi:
[ 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])
Generatori annidati
Le list comprehensions possono anche disegnare elementi da liste multiple, nel qual caso il risultato sarà l'elenco di ogni possibile combinazione dei due elementi, come se le due liste fossero elaborate in modo annidato . Per esempio,
[ (a,b) | a <- [1,2,3], b <- ['a','b'] ]
-- [(1,'a'), (1,'b'), (2,'a'), (2,'b'), (3,'a'), (3,'b')]
Comprensioni parallele
Con l' estensione della lingua di Parallel List Comprehensions ,
[(x,y) | x <- xs | y <- ys]
è equivalente a
zip xs ys
Esempio:
[(x,y) | x <- [1,2,3] | y <- [10,20]]
-- [(1,10),(2,20)]
Attacchi locali
Le list comprehensions possono introdurre binding locali per le variabili in modo da contenere alcuni valori provvisori:
[(x,y) | x <- [1..4], let y=x*x+1, even y] -- [(1,2),(3,10)]
Lo stesso effetto può essere ottenuto con un trucco,
[(x,y) | x <- [1..4], y <- [x*x+1], even y] -- [(1,2),(3,10)]
Le let
in-list comprehensions sono ricorsive, come al solito. Ma i binding del generatore non lo sono, il che abilita lo shadowing :
[x | x <- [1..4], x <- [x*x+1], even x] -- [2,10]
Notazione
La lista per la comprensione può essere corrispondentemente codificato con la lista monade di do
la notazione .
[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 }
Le guardie possono essere gestite usando Control.Monad.guard
:
[x | x <- xs, even x] do { x <- xs ; guard (even x) ; return x }