Haskell Language
Zrozumienie listy
Szukaj…
Podstawowe pojęcia dotyczące list
Haskell ma opisy list , które są podobne do zestawów rozumianych w matematyce i podobnych implementacji w imperatywnych językach, takich jak Python i JavaScript. W najprostszym z nich zestawienia list mają następującą postać.
[ x | x <- someList ]
Na przykład
[ x | x <- [1..4] ] -- [1,2,3,4]
Funkcje można również zastosować bezpośrednio do x:
[ f x | x <- someList ]
Jest to równoważne z:
map f someList
Przykład:
[ x+1 | x <- [1..4]] -- [2,3,4,5]
Wzory w wyrażeniach generatora
Jednak x
w wyrażeniu generatora jest nie tylko zmienne, ale może być dowolnym wzorem. W przypadku niedopasowania wzoru wygenerowany element jest pomijany, a przetwarzanie listy jest kontynuowane z kolejnym elementem, działając w ten sposób jak filtr:
[x | Just x <- [Just 1, Nothing, Just 3]] -- [1, 3]
Generator ze zmienną x
we wzorze tworzy nowy zakres zawierający wszystkie wyrażenia po jego prawej stronie, gdzie x
jest zdefiniowane jako wygenerowany element.
Oznacza to, że strażnicy mogą być kodowani jako
[ x | x <- [1..4], even x] ==
[ x | x <- [1..4], () <- [() | even x]] ==
[ x | x <- [1..4], () <- if even x then [()] else []]
Gwardia
Inną cechą opisów listowych są strażnicy, które działają również jak filtry. Strażniki są wyrażeniami logicznymi i pojawiają się po prawej stronie paska w formie listy.
Ich najbardziej podstawowym zastosowaniem jest
[x | p x] === if p x then [x] else []
Każda zmienna użyta w osłonie musi pojawić się po lewej stronie w zrozumieniu lub w inny sposób mieć zasięg. Więc,
[ f x | x <- list, pred1 x y, pred2 x] -- `y` must be defined in outer scope
co jest równoważne z
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])
(operator >>=
to infixl 1
, tzn. kojarzy (jest w nawiasie) po lewej). Przykłady:
[ 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])
Zagnieżdżone generatory
Wyrażenia listowe mogą również rysować elementy z wielu list, w takim przypadku wynikiem będzie lista każdej możliwej kombinacji dwóch elementów, tak jakby dwie listy były przetwarzane w sposób zagnieżdżony . Na przykład,
[ (a,b) | a <- [1,2,3], b <- ['a','b'] ]
-- [(1,'a'), (1,'b'), (2,'a'), (2,'b'), (3,'a'), (3,'b')]
Równoległe rozumienie
Z rozszerzeniem języka Parallel List Compstandingions ,
[(x,y) | x <- xs | y <- ys]
jest równa
zip xs ys
Przykład:
[(x,y) | x <- [1,2,3] | y <- [10,20]]
-- [(1,10),(2,20)]
Wiązania lokalne
Wyjaśnienia list mogą wprowadzać lokalne powiązania dla zmiennych w celu przechowywania niektórych wartości pośrednich:
[(x,y) | x <- [1..4], let y=x*x+1, even y] -- [(1,2),(3,10)]
Ten sam efekt można uzyskać za pomocą lewy,
[(x,y) | x <- [1..4], y <- [x*x+1], even y] -- [(1,2),(3,10)]
let
na liście są jak zwykle rekurencyjne. Ale powiązania z generatorem nie są, co umożliwia cieniowanie :
[x | x <- [1..4], x <- [x*x+1], even x] -- [2,10]
Czy notacja
Wszelkie listowego można odpowiednio zakodowane z liĹ monady za do
notacji .
[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 }
Strażnikami można się posługiwać za pomocą Control.Monad.guard
:
[x | x <- xs, even x] do { x <- xs ; guard (even x) ; return x }