Ranges and List Comprehensions
Prerequisites: List functions
Ranges
main :: IO ()
main = do
print [1 .. 10]
print [2, 4 .. 20]
print [10, 8 .. 1]
print ['a' .. 'f']
print (take 5 [100 ..])
[1,2,3,4,5,6,7,8,9,10]
[2,4,6,8,10,12,14,16,18,20]
[10,8,6,4,2]
"abcdef"
[100,101,102,103,104]
[a .. b]counts fromatob, inclusive.- Give the first two elements to set the step:
[2, 4 .. 20]. - Counting down needs an explicit step:
[10 .. 1]is empty. [100 ..]is an infinite list — fine, because Haskell is lazy andtake 5only asks for five elements.
Avoid ranges of Double such as [0.1, 0.2 .. 1]: rounding makes the
last element surprising.
List comprehensions
A list comprehension builds a list from generators and conditions, much like set-builder notation in maths ({ 2x | x ∈ S, x > 3 }):
main :: IO ()
main = do
print [x * x | x <- [1 .. 10]]
print [x | x <- [1 .. 20], x `mod` 3 == 0]
print [(x, y) | x <- [1 .. 3], y <- "ab"]
print [(a, b, c) | c <- [1 .. 20], b <- [1 .. c], a <- [1 .. b], a * a + b * b == c * c]
print [c | c <- "Hello World", c `elem` ['A' .. 'Z']]
[1,4,9,16,25,36,49,64,81,100]
[3,6,9,12,15,18]
[(1,'a'),(1,'b'),(2,'a'),(2,'b'),(3,'a'),(3,'b')]
[(3,4,5),(6,8,10),(5,12,13),(9,12,15),(8,15,17),(12,16,20)]
"HW"
x <- listis a generator; with several generators, the later ones vary fastest (like nested loops).- Conditions after a comma are filters.
- Each generator can use variables from earlier ones (
b <- [1 .. c]).
let in comprehensions
main :: IO ()
main = do
let people = [("Ada", 36), ("Alan", 41), ("Grace", 85)]
print [name ++ " (" ++ show decade ++ "0s)" | (name, age) <- people, let decade = age `div` 10, age > 40]
["Alan (40s)","Grace (80s)"]
Generators can pattern match — (name, age) <- people pulls each
pair apart — and let names an intermediate value.
Practice
Use a comprehension to list all numbers from 1 to 50 that are divisible by 7 or end in 7.
Show solution
main :: IO ()
main = print [n | n <- [1 .. 50], n `mod` 7 == 0 || n `mod` 10 == 7]
[7,14,17,21,27,28,35,37,42,47,49]