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