Exercises

Prove the following using induction. You may need previously proven results.

Mult_0_r (n: Nat) : Equal Nat (Mult n Nat.zero) Nat.zero
Mult_0_r n = ?

Plus_n_sm (n: Nat) (m: Nat) : Equal Nat (Nat.succ (Plus n m)) (Plus n (Nat.succ m))
Plus_n_sm n m = ?

Plus_comm (n: Nat) (m: Nat) : Equal Nat (Plus n m) (Plus m n)
Plus_comm n m = ?

Add_0_r (n: Nat) : Equal Nat (Plus n Nat.zero) n
Add_0_r n = ?

Plus_assoc (n: Nat) (m: Nat) (p: Nat) : Equal Nat (Plus n (Plus m p)) (Plus (Plus n m) p)
Plus_assoc n m p = ?

Consider the following function that doubles its input.

Double (n: Nat)     : Nat
Double Nat.zero     = Nat.zero
Double (Nat.succ n) = Nat.succ (Nat.succ (Double n))

Use induction to prove the following theorems about Double:

Double_plus (n: Nat) : Equal Nat (Double n) (Plus n n)
Double_plus n = ?

Some theorems require analyzing the best way to prove them, for example, to prove that a number is even, we could prove it for its successor, but that would require us to prove it for the successor of the successor, making the proof of Evenb more difficult by induction. So it's important to realize when it is necessary and when it is not.

Evenb_s (n: Nat) : Equal Bool (Evenb (Nat.succ n)) (Notb  (Evenb n))
Evenb_s n = ?

Another case

Let's verify if the equality n +(m + 1) = 1 + (n + m) is true.

First, our problem:

Problems.t2 (n: Nat) (m: Nat) : Equal Nat (Plus n (Nat.succ m)) (Nat.succ(Plus n m))

We verify the base case, when n is zero:

Problems.t2 Nat.zero m = Equal.refl

and move on to the next case

Problems.t2 (Nat.succ n) m = ?

and our current goal becomes:

• Expected: Equal Nat (Nat.succ (Plus n (Nat.succ m))) (Nat.succ (Nat.succ (Plus n m)))

Translating, the successor of the addition of n and the successor of m is equal to the successor of the successor of the addition of n and m. To solve this problem, we will invoke induction:

let ind = Problems.t2 n m

and our current goal is to prove that:

• Expected: Equal Nat (Nat.succ (Plus n (Nat.succ m))) (Nat.succ (Nat.succ (Plus n m)))

Again, translating, that the successor of the addition of n and the successor of m is equal to the successor of the successor of the addition of n and m.

But now we have a very useful tool, our variable ind which is:

Equal Nat (Plus n (Nat.succ m)) (Nat.succ (Plus n m))

Now, analyzing our goal and our variable ind, we can see that it is enough to add Nat.succ to both sides of the induction, and it will be exactly the same as our goal. To do this, we will use a lambda function:

let app = Equal.apply (x => (Nat.succ x)) ind

And our variable app will return our goal:

Equal Nat (Nat.succ (Plus n (Nat.succ m))) (Nat.succ (Nat.succ (Plus n m)))

Just return app and Kind will give us the coveted All terms check.

Using other theorems

In Kind, as in informal mathematics, large proofs are often divided into a sequence of theorems, with later proofs referring to earlier theorems. But sometimes a proof will require some varied fact that is too trivial and of too little general interest to give it its own higher-level name. In these cases, it is convenient to be able to simply state and prove the necessary "sub-theorem" exactly at the point where it is used.

Let's analyze the following addition commutation theorem:

Problems.t3 (n: Nat) (m: Nat) : Equal Nat (Plus n  m) (Plus m n)

In the first case, for n and m equal to zero we have a reflection:

Problems.t3 Nat.zero Nat.zero = Equal.refl

So we move on to the next case:

Problems.t3 (Nat.succ n) m = ?

And here it seems that we have a new problem:

Expected: Equal Nat (Nat.succ (Plus n m)) (Plus m (Nat.succ n))

Analyzing the problem, we realize that there is a theorem already proven within it, that the successor of the addition of two numbers is equal to the addition of one number with its successor, so we can use that to our advantage.

We will start by applying a Nat.succ to our original problem:

let ind_a = Equal.apply (x => (Nat.succ x)) (Problems.t3 n m )

Then we invoke our already solved problem, Problems.t2:

let ind_b = Problems.t2 m n

When we give the Type Check, the terminal returns:

+ INFO  Inspection.

   • Expected: (Equal Nat (Nat.succ (Plus n m)) (Plus m (Nat.succ n))) 

   • Context: 
   •   n     : Nat 
   •   m     : Nat 
   •   ind_a : (Equal Nat (Nat.succ (Plus n m)) (Nat.succ (Plus m n))) 
   •   ind_a = (Equal.apply Nat Nat (Plus n m) (Plus m n) (x => (Nat.succ x)) (Problems.t3 n m)) 
   •   ind_b : (Equal Nat (Plus m (Nat.succ n)) (Nat.succ (Plus m n))) 
   •   ind_b = (Problems.t2 m n) 
 
   let ind_b = Problems.t2 m n
     ?
     ┬
     └Here!

Now we can see that the first part of ind_a is the inverse of the first part of our goal and the first part of ind_b is equal to the second part of the goal, we just need to organize and join the necessary parts. To do this, we will use Equal.mirror and Equal.chain.

let ind_c = Equal.chain ind_b Equal.mirror ind_a

And ind_c returns a value similar to the desired one:

• Expected: Equal Nat (Nat.succ (Plus n m)) (Plus m (Nat.succ n))
•   ind_c : Equal Nat (Plus m (Nat.succ n)) (Nat.succ (Plus n m))

We can see that one is the other mirrored, to make them equal, we will use Equal.mirror again:

let app = Equal.mirror ind_c

When we call app, the Type Check returns the message All terms checked and thus we prove, through induction and using another proof, the commutation of addition, that the sum of n and m is equal to the sum of m and n.