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[],
whereqis a sequence of zero or more qualifiers. | 
| (ZF2) | [ e | v <- f:fs, q ]reduces to[ e | q ] [ v := f ] ++ [ e | v <- fs, q ],
whereh [ v := f ]representshwith all
occurrences ofvin it replaced byf. | 
| (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)