Haskell by Example: List Comprehensions
Creating and transforming lists concisely with this sample code demonstrating set-builder notation syntax, generators with left arrow operator, predicate filters for conditions, and multiple generators for Cartesian products.
Code
-- Generate a list of squares for numbers 1 to 10
squares :: [Int]
squares = [x^2 | x <- [1..10]]
-- Filter: Get only even numbers from a list
evens :: [Int] -> [Int]
evens xs = [x | x <- xs, even x]
-- Combine two lists (Cartesian product)
pairs :: [Int] -> [Int] -> [(Int, Int)]
pairs listA listB = [(a,b) | a <- listA, b <- listB]
-- FizzBuzz logic using comprehension
fizzbuzz :: Int -> [String]
fizzbuzz n = [check x | x <- [1..n]]
where check x | x `mod` 15 == 0 = "FizzBuzz"
| x `mod` 3 == 0 = "Fizz"
| x `mod` 5 == 0 = "Buzz"
| otherwise = show xExplanation
List comprehensions in Haskell provide concise syntax for creating new lists from existing ones, inspired by mathematical set-builder notation. The general structure [ output_expression | generators, filters ] mirrors set notation like { 2x | x ∈ ℕ, x ≤ 10 }. List comprehensions combine three functional programming patterns: generation, filtering, and mapping into a single declarative expression.
Generators introduce variables ranging over list elements using the left arrow <- operator, read as "drawn from" or "belongs to". The expression x <- [1..10] binds x to each element from 1 to 10 sequentially. Predicates are boolean expressions acting as filters, placed after generators and separated by commas. Only elements satisfying all predicates are included in the result list. Multiple predicates can be chained, requiring elements to satisfy every condition.
Multiple generators create Cartesian products, with the rightmost generator iterating fastest like an innermost loop in imperative programming. The comprehension [(x,y) | x <- xs, y <- ys] produces all pairs combining each element from xs with each element from ys. While resembling set-builder notation, list comprehensions produce lists not sets, preserving order and allowing duplicate elements.
Code Breakdown
x <- [1..10] generator binds x to each element sequentially.even x predicate filter, includes only elements satisfying condition.a <- listA, b <- listB multiple generators create Cartesian product.where check x | ... guards provide conditional logic within comprehension.
