Skip to content
AgileLogics
5 min read

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 from a to b, 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 and take 5 only 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 <- list is 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]