Haskell Language
Lista förståelser
Sök…
Grundläggande listförståelser
Haskell har listförståelser , som liknar uppsatta förståelser i matematik och liknande implementeringar på nödvändiga språk som Python och JavaScript. På deras mest grundläggande har listförståelse följande form.
[ x | x <- someList ]
Till exempel
[ x | x <- [1..4] ] -- [1,2,3,4]
Funktioner kan också tillämpas direkt på x:
[ f x | x <- someList ]
Detta motsvarar:
map f someList
Exempel:
[ x+1 | x <- [1..4]] -- [2,3,4,5]
Mönster i generatoruttryck
Emellertid är x
i generatoruttrycket inte bara variabelt, utan kan vara vilket mönster som helst. I fall av mönstermatchning hoppas det genererade elementet över, och bearbetningen av listan fortsätter med nästa element, vilket således fungerar som ett filter:
[x | Just x <- [Just 1, Nothing, Just 3]] -- [1, 3]
En generator med en variabel x
i sitt mönster skapar nytt omfång som innehåller alla uttryck till höger, där x
definieras som det genererade elementet.
Detta innebär att skydd kan kodas som
[ x | x <- [1..4], even x] ==
[ x | x <- [1..4], () <- [() | even x]] ==
[ x | x <- [1..4], () <- if even x then [()] else []]
vakter
En annan egenskap hos listförståelser är vakter, som också fungerar som filter. Vakter är booleska uttryck och visas på höger sida av fältet i en listaförståelse.
Deras mest grundläggande användning är
[x | p x] === if p x then [x] else []
Alla variabler som används i en skydd måste visas till vänster i förståelsen eller på annat sätt vara i omfattning. Så,
[ f x | x <- list, pred1 x y, pred2 x] -- `y` must be defined in outer scope
vilket motsvarar
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])
(operatören >>=
är infixl 1
, dvs den associerar (är parenteserad) till vänster). Exempel:
[ 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])
Kapslade generatorer
Listförståelser kan också dra element från flera listor, i vilket fall resultatet blir listan över alla möjliga kombinationer av de två elementen, som om de två listorna har bearbetats på det kapslade sättet. Till exempel,
[ (a,b) | a <- [1,2,3], b <- ['a','b'] ]
-- [(1,'a'), (1,'b'), (2,'a'), (2,'b'), (3,'a'), (3,'b')]
Parallella förståelser
Med språkförlängning med parallella listförståelser ,
[(x,y) | x <- xs | y <- ys]
är ekvivalent med
zip xs ys
Exempel:
[(x,y) | x <- [1,2,3] | y <- [10,20]]
-- [(1,10),(2,20)]
Lokala bindningar
Listförståelser kan introducera lokala bindningar för variabler för att hålla vissa mellanvärden:
[(x,y) | x <- [1..4], let y=x*x+1, even y] -- [(1,2),(3,10)]
Samma effekt kan uppnås med ett trick,
[(x,y) | x <- [1..4], y <- [x*x+1], even y] -- [(1,2),(3,10)]
let
inlisterna är som vanligt rekursiv. Men generatorbindningar är inte, vilket möjliggör skuggning :
[x | x <- [1..4], x <- [x*x+1], even x] -- [2,10]
Gör notation
Varje lista förståelse kan på motsvarande sätt kodas med listan monadens do
notation .
[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 }
Vakterna kan hanteras med Control.Monad.guard
:
[x | x <- xs, even x] do { x <- xs ; guard (even x) ; return x }