Haskell · syntax · lists
Haskell list comprehensions, explained
One of the first things that makes Haskell feel elegant is the list comprehension: a concise way to build a new list from existing ones, mirroring the mathematical set-builder notation you may remember from school. This guide explains the syntax, multiple generators, guards, and how comprehensions relate to map and filter.
The basic syntax
A list comprehension has the shape [ output | generator, condition ]. Read the bar as "such that":
-- the squares of 1 to 10
squares = [x*x | x <- [1..10]]
-- [1,4,9,16,25,36,49,64,81,100] Here x <- [1..10] is a generator: it draws each x from the list [1..10], and the part before the bar, x*x, is the output expression applied to every element.
Adding guards (filtering)
A guard is a boolean condition that keeps only the elements satisfying it:
-- even numbers from 1 to 20, doubled
result = [x*2 | x <- [1..20], even x]
-- [4,8,12,16,20,24,28,32,36,40] You can combine several guards, separated by commas; all must hold for an element to be included.
Multiple generators
With more than one generator, the comprehension iterates over every combination (like nested loops), in order:
-- all pairs from two small lists
pairs = [(x, y) | x <- [1,2,3], y <- ['a','b']]
-- [(1,'a'),(1,'b'),(2,'a'),(2,'b'),(3,'a'),(3,'b')] The rightmost generator varies fastest. You can also let a later generator depend on an earlier one — for example drawing y from [x..10].
How they relate to map and filter
A comprehension is essentially map and filter in one readable form. These are equivalent:
[x*2 | x <- xs, even x]
map (*2) (filter even xs) Use whichever reads better for the case. Comprehensions shine when you have multiple generators or several guards; map/filter compose nicely in point-free pipelines. Because Haskell is lazy, a comprehension over an infinite list like [1..] only computes the elements you actually consume.
FAQ
What is a generator in a list comprehension? The x <- xs part: it draws each value of x from the list xs to feed the output expression.
What is a guard? A boolean condition (like even x) placed after a comma; only elements for which it's true are kept.
Can I use multiple generators? Yes — the comprehension produces every combination, with the rightmost generator varying fastest, like nested loops.
Are comprehensions just map and filter? Conceptually yes for the simple cases; comprehensions are often more readable with multiple generators or guards, while map/filter compose well in pipelines.
For the language behind the syntax, see what Haskell is; comprehensions are one of the features that make it concise and expressive.