jonnifyfsharp

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.

C1.05.1 · part 1

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 name x.
tuple
(a, b) — matches a pair, binds each component.
cons
x :: rest — matches a non-empty list; x is the head, rest the 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
C1.05.1 · part 2

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

match [1; 2; 3] | [] empty? no — list is not empty skip | _ :: rest matches · head ignored, rest bound BINDS _ = 1 (head, ignored) rest = [2; 3] → 1 + length [2; 3]
match [1; 2; 3] · arm | _ :: rest fires · rest = [2; 3] · result = 1 + length [2; 3]

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 [] | [] matches the empty list → 0 · | _ :: rest matches a non-empty list → 1 + length rest ·
[] · arm | [] fires · binds nothing · result = 0
The four dispatches, computed by hand (the no-JS fallback)
inputarm that firesrest binds toresult
[]| []— (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

Related in this course