Dive C1.05.1
Match expressions
A pattern is a shape — match it, bind the pieces, run the arm.
A match expression tries a list of patterns against a
value, from top to bottom, and evaluates the result of the first that fits. A pattern is not a comparison: it is
a shape that decomposes the value and binds its parts. The arm x :: rest
matches any non-empty list and, in one step, binds x to the head and
rest to the tail. Order matters — the first matching arm wins — and
the compiler checks that the patterns cover every case, warning FS0025 when one is
missing.
The pattern kinds
A match arm is written | pattern -> result. The patterns
below are the building blocks. Each either matches the value or does not; a variable pattern always matches
and binds, a constant pattern matches only its exact value, and a structural pattern matches a shape and binds
the parts it pulls out.
let rec length xs = match xs with | [] -> 0 // constant: the empty list | _ :: rest -> 1 + length rest // cons: head ignored, tail bound to rest length [1; 2; 3] // val it : int = 3
- constant
0,'a',"hi",[]— matches that exact value.- wildcard
_— matches anything, binds nothing.- variable
x— matches anything, binds it to the namex.- tuple
(a, b)— matches a pair, binds each component.- cons
x :: rest— matches a non-empty list;xis the head,restthe tail.- as
(x :: _) as whole— binds the whole value while also decomposing it.
The function keyword is shorthand for a lambda that immediately matches its one
argument. The two definitions below are the same value.
let isZero = function 0 -> true | _ -> false // val isZero : int -> bool // the same value, written out let isZero = fun n -> match n with | 0 -> true | _ -> false isZero 0 // val it : bool = true
First match wins, and every case is checked
Arms are tried in source order; the result of the first matching arm is the value of the whole expression.
A variable or wildcard arm matches everything, so it belongs last — any arm after it is
unreachable, which the compiler reports. The compiler also checks the other direction: if the arms leave a
possible value unmatched, it warns FS0025 "Incomplete pattern matches on this expression"
and the missing case throws MatchFailureException at run time.
length xs · two arms, tried top to bottom
Two arms, tried in order, the first fit chosen. The cons arm names the head and tail in the same move that recognises the shape — recognition and binding are one step.
Dispatch an input through length
Pick a value below. The matcher tries | [] first, then | _ :: rest;
the readout names the arm that fires and what rest binds to. The static table holds
the same four answers, so the result is here whether or not the script runs.
match xs with [] | _ :: rest · which arm fires
| input | arm that fires | rest binds to | result |
|---|---|---|---|
| [] | | [] | — (nothing) | 0 |
| [1] | | _ :: rest | [] | 1 |
| [1; 2] | | _ :: rest | [2] | 2 |
| [1; 2; 3] | | _ :: rest | [2; 3] | 3 |
The empty list takes the first arm; every non-empty list takes the second, binding its tail. One
expression, two shapes, no if in sight.
Pattern
A shape that recognises a value and binds the parts it decomposes, in a single step.
F# today
| _ :: rest matches a non-empty list and names its tail rest at once.
Where this leads
The pattern kinds here recognise fixed shapes. The next dive adds a boolean test to an arm with a
when guard, combines cases with or-patterns, and shows that a pattern also works in a
let binding and a function parameter — so a tuple can be pulled apart on the way in.
References
Sources
- Microsoft — F# documentation — match expressions, the pattern kinds, and the
functionkeyword. - The F# Language Specification — the pattern grammar, match rules, and incomplete-match warnings.
- FSharp.Core API reference — the list type and the cons operator the patterns decompose.
Related in this course
- C1.05.2 — Guards & destructuring — the next refinement of these arms.
- C1.05 — Pattern matching — the module hub and its three dives.
- Elixir — Functional core — the same list/cons matching on the BEAM.