Pattern Matching

Functions

You can define multiple versions of the same function that produce different results depending on their input. These function definitions will pattern match whatever argument is passed in order of definition and produce an output based on a matching input. The example below shows that if a 7 is passed into the lucky function then it will return "LUCKY NUMBER SEVEN!" otherwise, if any other x is passed in it will return "Sorry, you're out of luck, pal!" If the x case had been defined first then lucky would only ever return the second case.

lucky :: (Integral a) => a -> String
lucky 7 = "LUCKY NUMBER SEVEN!"
lucky x = "Sorry, you're out of luck, pal!"

This sort of pattern matching allows you elegantly define recursive functions as the final state at the end of the recursion (in this case 0) which would usually be defined by an if in the body of the function in other languages is instead just pattern matched when the function is called, thus retaining the clarity of the original function.

factorial :: (Integral a) => a -> a
factorial 0 = 1
factorial n = n * factorial (n - 1)

Tuples

If you define a pattern matched function that doesn’t cover all input possibilities and you call it with a value outside of its defined patterns you will get an Non-exhaustive patterns error.

You can pattern match and destructure tuple arguments to functions directly in a function definition rather than referring to a tuple argument as a single variable like x. Instead you can express it as (x, y) to put the values within the tuple into the scope of your function directly.

addTuple (Num a) => (a, a) -> a
addTuple (x, y) = x + y

The less elegant solution would be to destructure the tuple inside the body of the function.

badTuple (Num a) => (a, a) ->
badTuple x = fst x + snd x

Lists

You can pattern match lists by using defining the name for the lists element you want to destructure to, followed by the : operator and then the list in the form x:myList

head' :: [a] -> a
head' (x:_) = x
head' [1, 2, 3]
-- 1

This can be extended to an arbitrary number of destructured variables.

combineHead :: [a] -> (a, a)
combineHead (x:y:_) = (x, y)
combineHead [1, 2, 3]
-- (1, 2)

You can also destructure. and pattern match lists directly if you know they are of a static length that is known beforehand. If this destructuring pattern is passed a list of the wrong length it will error with a non-exhaustive patterns error.

toTuple [x, y] = (x, y)
toTuple [3, 4] = (3, 4)
toTuple [3, 4, 5]
-- ERROR

You can also destructure lists in reverse, removing the first elements with an _ and pattern matching the rest of the list.

tail' :: [a] -> [a]
tail' (_:x) = x

As Patterns

As patterns allow you to pattern match structures while ALSO retaining the original structure. You can do this by putting a variable name that will contain the entire structure followed by a @ at the beginning of the pattern matching.

start word@(x:_) = "The first element of " ++ word ++ " is " ++ [x]
start "Hello"
-- The first element of Hello is H