[ x+y | x <- xs, y <-ys ]
is the same as
do {x <- xs; y <- ys; return (x + y)}
is the same as
xs >>= \x -> ys >>= \y -> return (x + y)
>>=
is called bind. What is being used here is the famous list monad. For lists, return is defined as return x = [x]
and bind is defined as xs >>= f = concatMap f xs
, and concatMap
is, as the name suggests, simply a composition of concat
and map
.
The idea behind the list monad is that with x <- xs
, you nondeterministically choose some arbitrary element of the list, then do some computation with it and in the end, you get a list of all the possible results you can get. So in your example,
do {x <- xs; y <- ys; return (x + y)}
chooses x
and y
nondeterministically from xs
and ys
, respectively, and you get a list of all possible results.
I will now leave it to you to use this knowledge to transform your list comprehension to an expression that uses only map
and concat
.
As for filter
, a condition b
in a list comprehensions is translated to guard b
in the list monad, which can be expressed with filter
if you want a non-monadic expression.