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:

PartialTotal alternative
head xslistToMaybe xs from Data.Maybe, or pattern match
tail xsdrop 1 xs, or uncons from Data.List
last xs, init xsunsnoc from Data.List (base 4.19+, GHC 9.8+)
xs !! ixs !? i from Data.List (base 4.19+), returns Maybe
maximum xscheck 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

FunctionExample
mapmap (*2) [1,2,3]
filterfilter even [1..10]
foldl'strict left fold from Data.List
foldrright fold, good for lazy lists
sort, sortOnsortOn snd pairs (Data.List)
reversereverse [1,2,3]
nubdedupe, O(n²), use a Set for big lists
groupgroup "aab" gives ["aa","b"]
take, drop, splitAtsplit by count
takeWhile, dropWhile, span, breaksplit by predicate
zip, zipWith, unzipcombine and separate lists
lookuplookup k pairs returns Maybe
concat, concatMapflatten
any, allboolean checks
elem, notElemmembership

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.