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 | 3matches any of the three.n when n < 0binds the value tonand 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