Formal Software Verification

5.2. Structured Constructs🔗

The four structured constructs are the term-mode counterparts of tactics from Lecture 4. fix x : α discharges a universally quantified goal by fixing an arbitrary x, as intro does for a ∀ in tactic mode. assume h : P discharges an implication by assuming its antecedent, as intro does for a →. have h : P := pf; rest names a proof pf of P as h for use in rest, the forward step that adds a fact to what is known. show P from pf restates the goal as P, definitionally, and supplies pf, which documents the proof and guides elaboration. A term-level let x := t; rest abbreviates a term, not a proof.

The composition of two implications, proved backwards in Lecture 4 as three "it suffices to" steps, reads forwards as two have steps that build the intermediate fact and then the conclusion.

namespace Forward theorem prop_comp (a b c : Prop) (hab : a b) (hbc : b c) : a c := assume ha : a; have hb : b := hab ha; show c from hbc hb end Forward

Read the proof as prose. Assume a. From ha and hab we have b, which we name hb. From hb and hbc we have c, which is the goal. Each have is one forward inference, and the proof term records the derivation top to bottom.

5.2.1. Examples🔗

The examples below use fix, assume, have, show and a term-level let, and each sits beside the tactic it mirrors.

Example 1. fix alone discharges a universally quantified goal, and the fun written the other way is the same term.

namespace Forward example : n : , n = n := fix n : ; rfl example : n : , n = n := fun n => rfl end Forward

Example 2. assume alone discharges an implication. The tactic proof uses intro for the same step.

namespace Forward example (a : Prop) : a a := assume h : a; h example (a : Prop) : a a := a:Propa a a:Proph:aa All goals completed! 🐙 end Forward

Example 3. fix and assume together prove the projection forwards, and the Lecture 4 script with intro and apply sits beside it.

namespace Forward example : a b : Prop, a b a := fix a b : Prop; assume ha : a; assume hb : b; ha example : a b : Prop, a b a := (a b : Prop), a b a a:Propb:Propha:ahb:ba All goals completed! 🐙 end Forward

Example 4. have inserts a forward step, naming the derived fact. The same proof inlines the term instead.

namespace Forward example (a b : Prop) (hab : a b) (ha : a) : b := have hb : b := hab ha; hb example (a b : Prop) (hab : a b) (ha : a) : b := hab ha end Forward

Example 5. show P from pf documents the goal, where a bare term leaves it implicit. The two proofs are the same.

namespace Forward example (a : Prop) (ha : a) : a := show a from ha example (a : Prop) (ha : a) : a := ha end Forward

Example 6. The composition of implications by two have steps, then the same proof inlined into a single application.

namespace Forward example (a b c : Prop) (hab : a b) (hbc : b c) : a c := assume ha : a; have hb : b := hab ha; show c from hbc hb example (a b c : Prop) (hab : a b) (hbc : b c) : a c := assume ha : a; hbc (hab ha) end Forward

Example 7. A term-level let abbreviates a value inside a proof. Here the two sides agree by computation once the let is unfolded.

namespace Forward example : (2 : ) + 2 = 4 := let n : := 2; (rfl : n + n = 4) end Forward

Example 8. A have names a fact that the rest of the proof uses more than once. Here the named implication is applied to two different hypotheses.

namespace Forward example (a b : Prop) (hab : a b) (ha ha' : a) : b b := have f : a b := hab; And.intro (f ha) (f ha') end Forward

Example 9. The same theorem in tactic mode and in structured term mode, so the correspondence is visible line by line.

namespace Forward example (a b : Prop) (hab : a b) (ha : a) : b := a:Propb:Prophab:a bha:ab All goals completed! 🐙 example (a b : Prop) (hab : a b) (ha : a) : b := show b from hab ha end Forward

Example 10. show may restate the goal in a definitionally equal but syntactically different form, since ¬ a unfolds to a → False, and term mode accepts the change.

namespace Forward example (a : Prop) (h : a False) : ¬ a := show a False from h end Forward