Formal Software Verification

5.1. Forward Proofs and the PAT Principle🔗

A forward proof starts at the hypotheses and derives new facts until it reaches the goal. Its characteristic phrase is "from … we have …", the mirror of Lecture 4's "it suffices to prove". Given the hypotheses ha : a, hab : a → b, hbc : b → c and the goal c, the forward reading builds b from ha and hab, then c from b and hbc, exactly the direction that a natural deduction derivation admits when read downwards from its assumptions.

A structured proof is a term whose shape follows the proposition it proves. A proof of a universally quantified statement fixes an arbitrary variable; a proof of an implication assumes its antecedent; a proof of a conjunction or an existential is built with the anonymous constructor; and intermediate facts are named as the proof proceeds. Lean writes these four shapes as fix, assume, the anonymous constructor ⟨…, …⟩, and have, with show to restate the current goal.

The reading that unifies term mode and tactic mode is the PAT principle, propositions as types and proofs as terms.W. A. Howard, "The formulae-as-types notion of construction", in To H. B. Curry: Essays on Combinatory Logic, Lambda Calculus and Formalism, Academic Press, 1980, pp. 479–490. A proposition is a type, and a proof of it is a term of that type. Under this reading an implication a → b is at once a logical statement and the type of functions from proofs of a to proofs of b, so a proof of an implication is a function, as Lecture 1 already hinted. A universally quantified statement ∀ x, P x is a dependent function type, whose result type P x depends on the argument x, and the single arrow of dependent function types accounts for both → and ∀.J. Avigad, L. de Moura, S. Kong, S. Ullrich, Theorem Proving in Lean 4, the chapter on propositions and proofs.

The constructs fix and assume are not part of Lean's core. They come from the LoVe support library, Lectures/LoVe/LoVelib.lean, which the import chain of these notes makes available, and they are term parsers that expand fix x : τ; e and assume h : P; e to the anonymous functions fun x : τ ↦ e and fun h : P ↦ e. The proof of the three-argument projection below shows the structured shape. It fixes the two propositions, assumes the two hypotheses, and states the goal it returns.

namespace Forward theorem fst_of_two_props : a b : Prop, a b a := fix a b : Prop; assume ha : a; assume hb : b; show a from ha end Forward

Because fix and assume are literally fun, the same theorem written with fun, and the variant that drops the final show, elaborate to the identical term.

namespace Forward theorem fst_of_two_props_no_show : a b : Prop, a b a := fix a b : Prop; assume ha : a; assume hb : b; ha theorem fst_of_two_props_fun : a b : Prop, a b a := fun a b ha hb => ha end Forward

That a proof is a function is not a metaphor but the literal state of affairs, and #check makes it visible. The identity proof of a → a is the identity function, and assume prints back as the fun it abbreviates.

fun a h => h : (a : Prop), a a#check (fun (a : Prop) (h : a) => h) fun h => h : True True#check (assume h : True; h)
fun a h => h :  (a : Prop), a  a
fun h => h : True  True