6.3. Pattern Matching Expressions
Lecture 3 wrote a function as top-level equations, one per constructor shape. The same power is available as a match expression usable wherever a term is expected, and as if c then … else … for a decidable condition. A match elaborates through the type's recursor, its casesOn of §6.1 in the simplest cases, and if branches on a Decidable instance for its condition. Patterns are tried top to bottom, so an earlier pattern shadows a later one, and the wildcard _ matches anything.
namespace Func
def classify (n : ℕ) : String :=
match n with
| 0 => "zero"
| 1 => "one"
| _ => "many"
def pred? : ℕ → Option ℕ
| 0 => none
| n + 1 => some n
end Func
The Option type packages a partial result, some x for a value and none for its absence, so pred? is total although the predecessor of 0 is undefined.
6.3.1. Examples
The examples below use match and if inside a body, on numbers, pairs, lists, and options.
Example 1. A match returning a classification, its wildcard catching every remaining case.
namespace Func
example : classify 7 = "many" := rfl
end Func
Example 2. if tests a decidable condition, here whether a number is zero.
namespace Func
def isZero (n : ℕ) : Bool :=
if n = 0 then true else false
example : isZero 0 = true := rfl
end Func
Example 3. A match on a pair inspects both components at once.
namespace Func
def bothZero (p : ℕ × ℕ) : Bool :=
match p with
| (0, 0) => true
| _ => false
example : bothZero (0, 3) = false := rfl
end Func
Example 4. pred? returns none at zero, so the result is always defined.
namespace Func
example : pred? 0 = none := rfl
end Func
Example 5. A match on a list returns the head as an option.
namespace Func
def firstOpt {α : Type} : List α → Option α
| [] => none
| x :: _ => some x
example : firstOpt [3, 1] = some 3 := rfl
end Func
Example 6. A match on an option unpacks some and supplies a default for none.
namespace Func
def orZero : Option ℕ → ℕ
| none => 0
| some n => n
example : orZero (some 5) = 5 := rfl
end Func
Example 7. Patterns are tried top to bottom, so the specific case precedes the wildcard.
namespace Func
def sign (n : ℤ) : String :=
match n with
| 0 => "zero"
| _ => "nonzero"
example : sign 0 = "zero" := rfl
end Func
Example 8. A match may appear inside a larger term, here inside an addition.
namespace Func
def bump (o : Option ℕ) : ℕ :=
1 + (match o with
| none => 0
| some n => n)
example : bump (some 4) = 5 := rfl
end Func
Example 9. if and a two-branch match decide the same condition.
namespace Func
def isZeroMatch (n : ℕ) : Bool :=
match n with
| 0 => true
| _ => false
example : isZeroMatch 0 = isZero 0 := rfl
end Func
Example 10. A safe division returning none when the divisor is zero.
namespace Func
def safeDiv (m n : ℕ) : Option ℕ :=
if n = 0 then none else some (m / n)
example : safeDiv 6 0 = none := rfl
end Func