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 }


Modified text is an extract of the original Stack Overflow Documentation
Autorizzato sotto CC BY-SA 3.0
Non affiliato con Stack Overflow