Structural induction in haskell
Structural induction is a proof method to prove the correctness of propositions or theorems in math.
For example, prove that for all positive integers, sum(1+2+..n) = n*(n+1)/2
using mathematical induction.
Base case:
sum(1) = 1 = 1 * (1+1)/2 proved for 1
Induction hypothesis:
sum(1+2+..+n) = n*(n+1)/2 assume true for n
Induction case(prove for n+1):
sum(1+2+..+n+1) = sum(1+2+..+n) + n+1 (definition of sum)
= n*(n+1)/2 + n+1 (IH)
= n*(n+1)+2(n+1)/2 (math computation)
= (n+1)*(n+2)/2 (RHS proved)
In principal, the proof procedure has 3 steps:
- show or prove base case. This is induction start.
- assume true of f(n). This is induction hypothesis(IH).
- prove f(n+1). This is induction step.
In haskell, it is used to prove the properties of recursive data structure or type class. Proof involves:
- substitution equals for equals. It’s the way reasoning about haskell programs.
- unfold definition.
- fold back to definition.
- use already known facts or lemmas.
- use induction hypothesis.
Reference: https://www.cs.princeton.edu/~dpw/cos441-11/notes/slides03B-Haskell-Intro.pdf
Example
Prove that length(l1 ++ l2) = length(l1) + length(l2) for all list l1 and l2
.
Induction of l1
case l1 is []: (base case)
length(l1 ++ l2) = length([] ++l2) (seqeq)
= length(l2) (unfold ++)
= 0 + length(l2) (math)
= length [] + length(l2) (fold length)
= length(l1) + length(l2) (RHS proved)
case l1 is (x:xs): (induction case)
IH: length(xs + l2) = length(xs) + length(l2)
length((x:xs) ++ l2) = length(x : (xs ++ l2)) (unfold ++)
= 1 + length(xs ++l2) (unfold length)
= 1 + length(xs) + length(I2) (IH)
= length(x:xs) + length(l2) (fold length, RHS proved)