Proof by Application

Our first tool for proving non-trivial theorems will be applying functions to both sides of an equality. For this, we will use the function Equal.apply, which takes an equality (Equal) and a function, and applies this function to both sides of the equality, generating a new equality.

For example:

Example_apply (n: Nat) (m: Nat) (e: Equal Nat m n) : Equal Nat (Nat.succ m) (Nat.succ n)
Example_apply n m e = ?

What do we have here? We have a proof that takes another proof/equality as argument. This means that we will carry out our proof assuming that the proof given as argument is also true. So, reading the statement of the proof, we have: "Given two naturals, m and n, and a proof that they are equal, prove that Nat.succ m and Nat.succ n are also equal".

We learned in our math classes that applying a function to both sides of an equality preserves the equality (x/2 = 3 -> 2x/2 = 23), and we can see that to prove what we want, we need to apply the function Nat.succ to both sides of e, using Equal.apply.

+ INFO  Inspection.

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

  • Context: 
  •   n : Nat 
  •   m : Nat 
  •   e : (Equal Nat m n) 

  Example_apply n m e = ?
                        ┬
                        └Here!

How does Equal.apply work: It takes as first argument the function to be applied to both sides, and as second argument the equality to which to apply the function. If you didn't understand the passage of the argument function (x => Nat.succ x), it is what we call a lambda function, and is also known as an anonymous function. Lambda functions are identified by their arrow =>, where on the left side of the arrow is the name of the function argument - use any name you want - and on the right side is the body of the function: what it returns. Our current lambda function is a function that takes any x and returns Nat.succ x.

We can see the result of this by check the file:

+ INFO  Inspection.

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

  • Context: 
  •   n : Nat 
  •   m : Nat 
  •   e       : (Equal Nat m n) 
  •   e_apply : (Equal Nat (Nat.succ m) (Nat.succ n)) 
  •   e_apply = (Equal.apply Nat Nat m n (x => (Nat.succ x)) e) 

  let e_apply = Equal.apply (x => Nat.succ x) e
      ?
      ┬
      └Here!

As e_apply is an equality of type Equal Nat (Nat.succ m) (Nat.succ n), the proof we are looking for is simply to return it, and we will have concluded our proof.

Example_apply (n: Nat) (m: Nat) (e: Equal Nat m n) : Equal Nat (Nat.succ m) (Nat.succ n)
Example_apply n m e =
  let e_apply = Equal.apply (x => Nat.succ x) e
  e_apply
  All terms checked.