Zoeken…


Algemene lijstbegrippen

Haskell heeft lijstbegrippen , die veel lijken op setbegrippen in wiskunde en vergelijkbare implementaties in imperatieve talen zoals Python en JavaScript. In hun meest elementaire vorm hebben lijstbegrippen de volgende vorm.

[ x | x <- someList ]

Bijvoorbeeld

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

Functies kunnen ook rechtstreeks op x worden toegepast:

[ f x | x <- someList ]

Dit komt overeen met:

map f someList

Voorbeeld:

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

Patronen in generatoruitdrukkingen

x in de generatoruitdrukking is echter niet alleen variabel, maar kan elk patroon zijn. In geval van patroonafwijking wordt het gegenereerde element overgeslagen en gaat de verwerking van de lijst verder met het volgende element, waardoor het als een filter werkt:

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

Een generator met een variabele x in zijn patroon creëert een nieuw bereik met alle expressies aan de rechterkant, waarbij x is gedefinieerd als het gegenereerde element.

Dit betekent dat bewakers kunnen worden gecodeerd als

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

Guards

Een ander kenmerk van lijstbegrippen zijn bewakers, die ook als filters fungeren. Bewakers zijn Booleaanse uitdrukkingen en verschijnen aan de rechterkant van de balk in een lijstbegrip.

Hun meest elementaire gebruik is

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

Elke variabele die in een bewaker wordt gebruikt, moet links van het begrip worden weergegeven of anderszins binnen het bereik vallen. Zo,

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

wat gelijk is aan

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])

(de operator >>= is infixl 1 , dat wil zeggen dat deze links wordt gekoppeld (tussen haakjes staat). Voorbeelden:

[ 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])

Geneste generatoren

Lijstbegrippen kunnen ook elementen uit meerdere lijsten trekken, in welk geval het resultaat de lijst is van elke mogelijke combinatie van de twee elementen, alsof de twee lijsten op de geneste manier zijn verwerkt. Bijvoorbeeld,

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

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

Parallelle begrippen

Met de extensie Parallel List Comprehensions ,

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

is gelijk aan

zip xs ys

Voorbeeld:

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

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

Lokale bindingen

Lijstbegrippen kunnen lokale bindingen introduceren voor variabelen die sommige tussentijdse waarden kunnen bevatten:

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

Hetzelfde effect kan worden bereikt met een truc,

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

Het let in Lijstcomprehensies is recursieve, zoals gebruikelijk. Maar generatorbindingen zijn dat niet, wat schaduwen mogelijk maakt:

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

Notatie

Elke lijstcomprehensie kan dienovereenkomstig worden gecodeerd met de lijst monade do notatie .

[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 }

De bewakers kunnen worden behandeld met 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
Licentie onder CC BY-SA 3.0
Niet aangesloten bij Stack Overflow