Formal Software Verification

3.6. Theorem Statements🔗

A theorem is a definition whose type is a proposition. Stating it requires no proof; the placeholder sorry stands where the proof will go, and Lean flags every use of it. The statements below specify the functions of this lecture, and the namespace keeps their names from clashing with Mathlib's.

namespace SorryTheorems theorem declaration uses `sorry`add_comm (m n : ) : add m n = add n m := m:n:add m n = add n m All goals completed! 🐙 theorem declaration uses `sorry`add_assoc (l m n : ) : add (add l m) n = add l (add m n) := l:m:n:add (add l m) n = add l (add m n) All goals completed! 🐙 theorem declaration uses `sorry`mul_comm (m n : ) : mul m n = mul n m := m:n:mul m n = mul n m All goals completed! 🐙 theorem declaration uses `sorry`mul_assoc (l m n : ) : mul (mul l m) n = mul l (mul m n) := l:m:n:mul (mul l m) n = mul l (mul m n) All goals completed! 🐙 theorem declaration uses `sorry`mul_add (l m n : ) : mul l (add m n) = add (mul l m) (mul l n) := l:m:n:mul l (add m n) = add (mul l m) (mul l n) All goals completed! 🐙 theorem declaration uses `sorry`reverse_reverse {α : Type} (xs : List α) : reverse (reverse xs) = xs := α:Typexs:List αreverse (reverse xs) = xs All goals completed! 🐙 end SorryTheorems

Computation cannot prove them. rfl settles add 2 7 = add 7 2, since both sides compute to 9, but in add m n = add n m the variables block computation, and the general law needs structural induction, the subject of the coming lectures.

Axioms are the other way to assert without proving, and they deserve more suspicion. An opaque constant has a type and no definition, and an axiom asserts a proposition with no proof at all. Nothing checks it, so an inconsistent axiom silently breaks the whole development. The course states axioms only to discuss them.

opaque a : opaque b : axiom a_less_b : a < b

3.6.1. Examples🔗

The examples below read the statements back, separate what computation settles from what it does not, and track which axioms a proof rests on. The namespace MoreTheorems keeps the new names clear of Mathlib.

Example 1. A statement with named binders is a universally quantified proposition.

SorryTheorems.add_comm : (m n : ), add m n = add n m#check @SorryTheorems.add_comm
SorryTheorems.add_comm :  (m n : ), add m n = add n m

Example 2. An implicit binder appears in braces, and the statement quantifies over the type as well.

@SorryTheorems.reverse_reverse : {α : Type} (xs : List α), reverse (reverse xs) = xs#check @SorryTheorems.reverse_reverse
@SorryTheorems.reverse_reverse :  {α : Type} (xs : List α), reverse (reverse xs) = xs

Example 3. The command #print axioms reports what a proof rests on, and sorry leaves the trace sorryAx.

'SorryTheorems.add_comm' depends on axioms: [sorryAx]#print axioms SorryTheorems.add_comm
'SorryTheorems.add_comm' depends on axioms: [sorryAx]

Example 4. A law that computation settles needs no induction. Zero on the right matches the first equation of add, so rfl proves it for every n.

namespace MoreTheorems theorem add_zero_right (n : ) : add n 0 = n := rfl end MoreTheorems 'MoreTheorems.add_zero_right' does not depend on any axioms#print axioms MoreTheorems.add_zero_right
'MoreTheorems.add_zero_right' does not depend on any axioms

Example 5. The same holds for the first equation of eval, whatever the environment.

namespace MoreTheorems theorem eval_num (env : String ) (i : ) : eval env (AExp.num i) = i := rfl end MoreTheorems MoreTheorems.eval_num : (env : String ) (i : ), eval env (AExp.num i) = i#check @MoreTheorems.eval_num
MoreTheorems.eval_num :  (env : String  ) (i : ), eval env (AExp.num i) = i

Example 6. A ground equation deserves a name as much as a general law does.

namespace MoreTheorems theorem fib_seven : fib 7 = 13 := rfl theorem reverse_nil : reverse ([] : List ) = [] := rfl end MoreTheorems

Example 7. Binders to the left of the colon and an explicit ∀ state the same proposition.

namespace MoreTheorems theorem all_add_zero : n : , add n 0 = n := fun _ => rfl end MoreTheorems MoreTheorems.all_add_zero : (n : ), add n 0 = n#check @MoreTheorems.all_add_zero
MoreTheorems.all_add_zero :  (n : ), add n 0 = n

Example 8. Applying a stated theorem to arguments instantiates the statement, whether or not a proof exists yet.

SorryTheorems.add_comm 2 3 : add 2 3 = add 3 2#check SorryTheorems.add_comm 2 3
SorryTheorems.add_comm 2 3 : add 2 3 = add 3 2

Example 9. Whatever a proof uses, #print axioms shows. The proof below rests on the axiom of this section, and on propext, which Mathlib's lemma uses.

namespace MoreTheorems theorem a_ne_b : a b := ne_of_lt a_less_b end MoreTheorems 'MoreTheorems.a_ne_b' depends on axioms: [a_less_b, propext]#print axioms MoreTheorems.a_ne_b
'MoreTheorems.a_ne_b' depends on axioms: [a_less_b, propext]

Example 10. Variables block computation, so the law below waits for structural induction and carries sorryAx in the meantime.

namespace MoreTheorems theorem declaration uses `sorry`half_double (n : ) : half (add n n) = n := n:half (add n n) = n All goals completed! 🐙 end MoreTheorems 'MoreTheorems.half_double' depends on axioms: [sorryAx]#print axioms MoreTheorems.half_double
'MoreTheorems.half_double' depends on axioms: [sorryAx]