To avoid doubt about “properties of lists” we can state properties using only code:
let rec append l1 l2 = match l1 with
| [] -> l2
| h::t -> h::(append t l2)
let rec sum = function [] -> 0
| h::t -> h + (sum t)Claim: ∀ℓ₁ : int list:
∀ℓ₂ : int list,
sum (append ℓ₁ ℓ₂) ≡ (sum ℓ₁) + (sum ℓ₂)Base Case: ℓ₁ = [].
let rev lst =
let rec tail_rev lst acc = match lst with
| [] -> acc
| h::t -> tail_rev t (h::acc)
in tail_rev lst []To prove that ∀ ℓ : 'a list, rev ℓ ≡ reverse ℓ, we’ll first prove:
Lemma.
ℓ₁,ℓ₂ : 'a list, (tail_rev ℓ₁ ℓ₂) ≡ (reverse ℓ₁) @ ℓ₂Base Case: ℓ₁ = [].
Inductive Case: Need to show
Informally we are proving that P(ℓ) is invariant over recursive calls.
Can’t you prove any (even false) thing(s) this way?
Consider “broken” versions of append, tail_rev:
(IH only tells about (badpend t l2))
(Base case is wrong…)
For any inductive type of the form:
The principle of induction for type t is:
For all x : t, P(x) if:
v : b, P(C₀ v), andx : t, v : b₁, P(x) ⇒ P(C₁(v,x))Examples:
nat: ∀ n : nat, P(n) if P(Zero) and ∀ m, P(m) ⇒ P(Succ m)'a list: ∀ ℓ : 'a list, P(ℓ) ifP([]) and ∀ x : 'a, ∀ ℓ : 'a list, P(ℓ) ⇒ P(x::ℓ)More Generalized Induction…
Principle of structural induction for bitlist:
∀
ℓ : bitlist,P(ℓ)if:
P(C0), andP(C1), and- ∀ ℓ,
P(ℓ) ⇒ P(L0 ℓ), and- ∀ ℓ,
P(ℓ) ⇒ P(L1 ℓ)
Notice: Here we have two base cases, and two step cases.
let rec bitlen blst = match blst with
| C0 | C1 -> 1
| L0 b | L1 b -> 1 + (bitlen b)
let rec bitweight blst = match blst with
| C0 -> 0
| C1 -> 1
| L0 b -> bitweight b
| L1 b -> 1 + (bitweight b)Prove: ∀ bl : bitlist, bitweight bl <= bitlen bl
Prove: ∀ bl : bitlist, bitweight bl <= bitlen bl
Base Cases:
bitweight C0 <= bitlen C0
bitweight C1 <= bitlen C1
cs2041.org