Haskell Cheatsheet
Lists and Tuples
Use this Haskell reference while you build software engineering projects, review code for technical interview prep, or polish examples for a software engineer resume.
Lists
nums :: [Int] nums = [1, 2, 3, 4]
Lists are singly linked lists. Prepending with : is O(1), while ++ and indexing with !! are O(n).
Partial Functions: head, tail, last, init
head, tail, last, init, maximum, minimum, foldr1, and !! crash on the empty list. GHC 9.8+ warns on head and tail by default (-Wx-partial). Prefer total alternatives:
| Partial | Total alternative |
|---|---|
head xs | listToMaybe xs from Data.Maybe, or pattern match |
tail xs | drop 1 xs, or uncons from Data.List |
last xs, init xs | unsnoc from Data.List (base 4.19+, GHC 9.8+) |
xs !! i | xs !? i from Data.List (base 4.19+), returns Maybe |
maximum xs | check null xs first, or fold to a Maybe |
safeHead :: [a] -> Maybe a safeHead [] = Nothing safeHead (x:_) = Just x -- uncons splits head and tail safely uncons [1,2,3] -- Just (1, [2,3]) uncons [] -- Nothing
List Construction
1 : [2,3] -- [1,2,3] [1,2] ++ [3,4] -- [1,2,3,4] [1..5] -- [1,2,3,4,5] [2,4..10] -- [2,4,6,8,10] take 5 [1..] -- [1,2,3,4,5], lists can be infinite
List Comprehensions
squares = [x * x | x <- [1..10]] evens = [x | x <- [1..20], even x] pairs = [(x, y) | x <- [1..3], y <- [1..2]]
Comprehensions combine generators and filters.
Common List Functions
| Function | Example |
|---|---|
map | map (*2) [1,2,3] |
filter | filter even [1..10] |
foldl' | strict left fold from Data.List |
foldr | right fold, good for lazy lists |
sort, sortOn | sortOn snd pairs (Data.List) |
reverse | reverse [1,2,3] |
nub | dedupe, O(n²), use a Set for big lists |
group | group "aab" gives ["aa","b"] |
take, drop, splitAt | split by count |
takeWhile, dropWhile, span, break | split by predicate |
zip, zipWith, unzip | combine and separate lists |
lookup | lookup k pairs returns Maybe |
concat, concatMap | flatten |
any, all | boolean checks |
elem, notElem | membership |
Laziness, foldl', and Strictness
Haskell is lazy: foldl (+) 0 [1..10^7] builds ten million unevaluated thunks before adding anything and can overflow the stack. Force evaluation where you accumulate:
import Data.List (foldl') total = foldl' (+) 0 [1..10000000] -- strict accumulator, constant space x `seq` y -- evaluate x (to WHNF), then return y f $! x -- strict application: force x before calling f
Bang patterns (on by default under GHC2021) make bindings strict:
count :: Int -> [a] -> Int count !acc [] = acc count !acc (_:xs) = count (acc + 1) xs
Rule of thumb: foldr for lazy or short-circuiting consumption, foldl' for strict accumulation (sums, counters), and plain foldl almost never.
Tuples
point :: (Double, Double) point = (3.0, 4.0) nameAge :: (String, Int) nameAge = ("Ada", 36) first = fst nameAge second = snd nameAge zip [1,2] "ab" -- [(1,'a'),(2,'b')] unzip [(1,'a'),(2,'b')] -- ([1,2],"ab")
Tuples are fixed-size and can hold mixed types. For named fields, prefer records.