Unit 4: List comprehensions
Introduction
List comprehensions are a convenient way of defining lists in Haskell. List comprehensions used to be called ZF-expressions. The following is an example of such an expression:
[ x * x | x <- [1, 2, 7, 12], even x ]
This list comprehension is the list of all those things of the form
x * x such that
x is drawn from the list
[1, 2, 7, 12]
and x is even.
Thus, the above evaluates to [4, 144].
The general form of a list comprehension is:
[ EXP | QUAL, ..., QUAL ]
where QUAL
is either a Boolean-valued expression or a generator.
A generator has one of two forms: either
VARIABLE <- LIST or
PATTERN <- LIST.
Alternative notation
The list comprehension displayed above can also be written
using the do-notation.
To use this you need to load the Control.Monad module:
ghci> import Control.Monad
ghci> do { x <- [1,2,7,12] ; guard (even x) ; return (x * x) }
[4,144]
This works because lists constitute a monad.
The do-notation is usually written
without using curly brackets and semicolons like this:
do x <- [1,2,7,12]
guard (even x)
return (x * x)
Reduction rules for list comprehensions
The behaviour of list comprehension is completely determined by the following five reduction rules:
| (ZF1) |
[ e | v <- [], q ] reduces to [],
where q is a sequence of zero or more qualifiers.
|
| (ZF2) |
[ e | v <- f:fs, q ] reduces to
[ e | q ] [ v := f ] ++ [ e | v <- fs, q ],
where h [ v := f ] represents h with all
occurrences of v in it replaced by f.
|
| (ZF3) |
[ e | False, q ] reduces to [].
|
| (ZF4) |
[ e | True, q ] reduces to [ e | q ].
|
| (ZF5) |
[ e | ] reduces to [ e ].
|
Quicksort
Hoare's Quicksort algorithm can be expressed very concisely by using a couple of list comprehensions:
quick :: Ord a => [a] -> [a]
quick [] = []
quick [x] = [x]
quick (x:xs) = quick [ u | u <- xs, u < x ]
++ [x] ++
quick [ u | u <- xs, u >= x ]
© Antoni Diller (17 September 2021)