These extensions enhance the abilities of Haskell’s list and comprehension syntaxes.
ParallelListComp
Available in: All recent GHC versions
The ParallelListComp
extension allows you to zip
multiple sub-comprehensions together. For example:
[ w + x + y + z | ((w, x), (y, z)) <- zip [ (w, x) | w <- ws, x <- xs ]
[ (y, z) | y <- ys, z <- zs ] ]
can be reduced to
[ w + x + y + z | w <- ws, x <- xs | y <- ys, z <- zs ]
Try it out!
{-# LANGUAGE ParallelListComp #-}
main = print [ (w, x, y, z) | w <- [1 .. 3],
x <- [2 .. 4]
| y <- [3 .. 5],
z <- [4 .. 6] ]
TransformListComp
Available in: All recent GHC versions
The TransformListComp
extension allows you to use SQL-like statements in list comprehensions.
then
clauses
You can use then
clauses to alter the list at that point in the comprehension. For example:
[ (x, y) | x <- xs,
y <- ys,
then reverse ]
A then
clause takes the form:
then f
where:
f :: forall a. [a] -> [a]
then by
clauses
You can use then by
clauses to alter the list at that point in the comprehension in a way that uses some combination of the prior bindings in that comprehension. For example:
[ (x, y) | x <- xs,
y <- ys,
then sortWith by (x + y) ]
A then by
clause takes the form:
then f by e
where, for some type t
:
f :: forall a. (a -> t) -> [a] -> [a]
e :: t
then group using
clauses
You can use then group using
clauses to group up the list at that point in the comprehension. For example:
[ (x, y) | x <- xs,
y <- ys,
then group using permutations ]
A then group using
clause takes the form:
then group using f
where:
f :: forall a. [a] -> [[a]]
Be aware that after the point of the then group using
clause, all bindings before the clause now have a different type. Specifically, if a binding x
had type t
before the clause, then it now has type [t]
after the clause.
then group by using
clauses
You can use then group by using
clauses to group up the list at that point in the comprehension in a way that uses some combination of the prior bindings in that comprehension. For example:
[ (x, y) | x <- xs,
y <- ys,
then group by (x + y) using groupWith ]
A then group by using
clause takes the form:
then group by e using f
where, for some type t
,
f :: forall a. (a -> t) -> [a] -> [[a]]
e :: t
A then group by using
clause has the same effect on the types of existing bindings as a then group using
clause does.
The the
function
The function the
(found in the GHC.Exts
module in the base
package) is sometimes useful with TransformListComp
. It takes a list, checks it to make sure that all values in the list are equal to each other, then returns the single unique value that the list holds. This is useful when grouping, where you might want to include a variable in the output but, since you’ve used a grouping clause, it’s now a list that contains just one unique value.
For example:
1 = the [1, 1, 1]
Example
Try it out!
{-# LANGUAGE TransformListComp #-}
import GHC.Exts (groupWith, the)
import Data.List (permutations)
main = print $ [ (x, y, map the v) | x <- [1 .. 10],
y <- [1 .. 10],
let v = x + y,
then group by v using groupWith,
then take 10,
then group using permutations,
t <- concat v,
then takeWhile by t < 3]
MonadComprehensions
Available in: GHC 7.2 or later
The MonadComprehensions
extension generalizes list comprehensions, including ParallelListComp
and TransformListComp
, to work for any Monad
(or MonadPlus
, or, in the case of ParallelListComp
, MonadZip
). This removes all limitations from list comprehensions relative to do
notation. For example:
[ (x, y) | x <- lookup e1 l,
y <- lookup e2 l,
then (\f -> maybe Nothing
(\x -> if f x == 2
then Just x
else Nothing))
by (x * y) ]
MonadComprehensions
automatically implies both ParallelListComp
and TransformListComp
, so you don’t have to activate them seperately.
The generalization of ParallelListComp
uses the MonadZip
type class, which is defined in the Control.Monad.Zip
module in the base
package; the use of guards requires the MonadPlus
type class, which is defined in the Control.Monad
module in the base
package.
Try it out!
{-# LANGUAGE TransformListComp, MonadComprehensions #-}
l :: [(String, Int)]
l = [("a", 1), ("b", 2), ("c", 3)]
main = print $ [ (x, y) | x <- lookup "a" l,
y <- lookup "b" l,
then (\f ->
maybe Nothing
(\x -> if f x == 2
then Just x
else Nothing))
by (x * y) ]
OverloadedLists
Available in: GHC 7.8 or later
TODO