Conditions: filter as a List Comprehension
The expression filter pred xs
can be written as the list comprehension
[x | x <- xs, pred x]
. This describes the list of all values x
taken from
the list xs
such that pred x
is true, just as what filter pred xs
would
produce. For example,
>>> [x | x <- [1..10], even x]
[2,4,6,8,10]
However, list comprehensions let us conveniently combine filtering and mapping:
>>> import Data.Char
>>> [chr x | x <- [65..90], even x]
"BDFHJLNPRTVXZ"
chr
is a function that constructs a character from its code point. The code
points of all uppercase English letters are 65 through 90. So this generates the
list of all uppercase letters with even code points, "BDFHJLNPRTVXZ"
.
And we can of course combine iterating over nested lists with mapping and filtering:
>>> [x * y | x <- [1..10], even x, y <- [x..10], odd (x + y)]
[6,10,14,18,20,28,36,42,54,72]
You should read this as follows: For every value x
taken from the list
[1..10]
that satisfies even x
(is even), take every value y
from the list
[x..10]
that satisfies odd (x + y)
and add the product x * y
to the list
produced by this list comprehension. (I'm not claiming that this is the most
meaningful example.)
Exercise
See whether you can come up with an expression that generates the same list as the list comprehension
[x * y | x <- [1..10], even x, y <- [x..10], odd (x + y)]
but which uses only standard list functions.
Solution
>>> import Data.List
>>> :{
| [1..10] & filter even
| & concatMap ( \x -> [x..10]
| & filter (\y -> odd (x + y))
| & map (\y -> x * y)
| )
| :}
[6,10,14,18,20,28,36,42,54,72]
To make this at least a little more readable, I used the operator (&)
from Data.List
. It's the flipped version of ($)
: f $ x
applies f
to x
. So does x & f
.
Here, we take the list [1..10]
and filter it, keeping only the elements
that are even. For each such element x
, we take the list and filter it
using the predicate \y -> odd (x + y)
. We replace each element y
in
the resulting list with x * y
. We obtain one such list of y
s for
each x
. By using concatMap
instead of map
, we end up concatenating
these lists.
I think we can agree that the list comprehension is the preferable solution.