Haskell Cheatsheet
Pattern Matching
Use this Haskell reference while you build software engineering projects, review code for technical interview prep, or polish examples for a software engineer resume.
Pattern Matching Basics
isZero :: Int -> Bool isZero 0 = True isZero _ = False
Patterns are tried from top to bottom. _ matches anything and ignores it.
Matching Lists
safeHead :: [a] -> Maybe a safeHead [] = Nothing safeHead (x:_) = Just x sumList :: [Int] -> Int sumList [] = 0 sumList (x:xs) = x + sumList xs
x:xs means a non-empty list with head x and tail xs.
Tuples and Nested Patterns
swap :: (a, b) -> (b, a) swap (x, y) = (y, x) addPair :: (Int, Int) -> Int addPair (a, b) = a + b
Patterns nest to any depth — match constructors inside constructors in one equation:
firstOfJust :: Maybe [a] -> Maybe a firstOfJust (Just (x:_)) = Just x firstOfJust _ = Nothing startsWith :: Maybe (Int, String) -> String startsWith (Just (0, s)) = "zero: " ++ s startsWith (Just (_, s)) = s startsWith Nothing = ""
(Just (x:_)) matches a Just whose payload is a non-empty list, binding its head — no manual unwrapping needed.
Case Expressions
describe :: Maybe Int -> String describe value = case value of Nothing -> "missing" Just n -> "value: " ++ show n
Use case when pattern matching inside an expression.
Guards in Case Alternatives
classify :: Maybe Int -> String classify value = case value of Nothing -> "missing" Just n | n < 0 -> "negative" | n == 0 -> "zero" | otherwise -> "positive"
Each case alternative can carry guards. If every guard fails, matching falls through to the next alternative.
Let and Where
circleArea r = let radiusSquared = r * r in pi * radiusSquared bmi weight height = category where value = weight / height ^ 2 category | value < 18.5 = "underweight" | value < 25 = "normal" | otherwise = "other"
let is an expression. where attaches helper definitions to an equation.
As-Patterns
describeAll :: String -> String describeAll s@(first:_) = "The string " ++ s ++ " starts with " ++ [first] describeAll [] = "Empty string"
s@pattern keeps both the whole value and the matched parts.
Lazy (Irrefutable) Patterns
lazyPair :: (Int, Int) -> Int lazyPair ~(a, b) = 1 -- never forces the pair splitFirst :: [Int] -> (Int, [Int]) splitFirst ~(x:xs) = (x, xs) -- crashes only if x or xs is used on []
~pattern always matches without evaluating the argument; the bindings fail only when actually used. Useful for avoiding needless evaluation in mutually dependent definitions.
View Patterns
{-# LANGUAGE ViewPatterns #-}
import Data.List (stripPrefix)
greet :: String -> String
greet (stripPrefix "Hello, " -> Just name) = "Hi " ++ name
greet _ = "Who are you?"With ViewPatterns, (f -> pattern) applies f to the argument and matches the result — handy for matching on a computed view instead of raw structure.