Skip to content
AgileLogics
6 min read

Pattern Matching Basics

Prerequisites: Tuples

match compares a value against a series of patterns and runs the first one that fits. Like if, it's an expression that returns a value:

let describe n =
    match n with
    | 0 -> "zero"
    | 1 | 2 | 3 -> "small"
    | n when n < 0 -> "negative"
    | _ -> "large"

for n in [0; 2; -7; 50] do
    printfn "%d is %s" n (describe n)
0 is zero
2 is small
-7 is negative
50 is large
  • Each case starts with |, then a pattern, then -> and the result.
  • 1 | 2 | 3 matches any of the three.
  • n when n < 0 binds the value to n and adds a guard condition.
  • _ is the wildcard — it matches anything, so it goes last.

Matching tuples

let fizzBuzz n =
    match n % 3, n % 5 with
    | 0, 0 -> "FizzBuzz"
    | 0, _ -> "Fizz"
    | _, 0 -> "Buzz"
    | _ -> string n

[1 .. 15] |> List.map fizzBuzz |> String.concat " " |> printfn "%s"
1 2 Fizz 4 Buzz Fizz 7 8 Fizz Buzz 11 Fizz 13 14 FizzBuzz

Matching lists

let summarize list =
    match list with
    | [] -> "empty"
    | [x] -> $"just {x}"
    | [x; y] -> $"{x} and {y}"
    | first :: rest -> $"{first} and {rest.Length} more"

printfn "%s" (summarize [])
printfn "%s" (summarize [7])
printfn "%s" (summarize [7; 8])
printfn "%s" (summarize [7; 8; 9; 10])
empty
just 7
7 and 8
7 and 3 more

first :: rest splits a list into its head and tail — the basis of many recursive functions:

let rec sum list =
    match list with
    | [] -> 0
    | head :: tail -> head + sum tail

printfn "%d" (sum [1; 2; 3; 4])
10

The compiler checks your cases

If you forget a case, F# warns you — incomplete matches are one of the most useful warnings in the language:

let sign n =
    match n with
    | 0 -> "zero"
    | n when n > 0 -> "positive"

printfn "%s" (sign 5)
main.fsx(2,11): warning FS0025: Incomplete pattern matches on this expression. For example, the value '1' may indicate a case not covered by the pattern(s). However, a pattern rule with a 'when' clause might successfully match this value.

positive

The script still runs, but sign -1 would throw a MatchFailureException. Treat this warning as an error — add the missing case.

function

function is shorthand for a one-parameter lambda that immediately matches on its argument:

let dayType =
    function
    | "Saturday" | "Sunday" -> "weekend"
    | _ -> "weekday"

printfn "%s %s" (dayType "Sunday") (dayType "Monday")
weekend weekday

Practice

Write a function that takes a (x, y) point and returns "origin", "on the x-axis", "on the y-axis", or "somewhere else".

Show solution
let where point =
    match point with
    | 0, 0 -> "origin"
    | _, 0 -> "on the x-axis"
    | 0, _ -> "on the y-axis"
    | _ -> "somewhere else"

for p in [(0, 0); (4, 0); (0, -2); (1, 1)] do
    printfn "%A: %s" p (where p)
(0, 0): origin
(4, 0): on the x-axis
(0, -2): on the y-axis
(1, 1): somewhere else