5.3. Forward Reasoning about Connectives and Quantifiers
Lecture 4 applied the rules of the connectives backwards with apply. Forwards, the same rules are used by juxtaposition, supplying the hypothesis directly. An elimination rule takes a hypothesis apart, and an introduction rule builds the goal. Thus And.left h and And.right h extract the two conjuncts, And.intro ha hb and the anonymous constructor ⟨ha, hb⟩ build a conjunction, Or.inl and Or.inr build a disjunction, Or.elim h f g consumes one with two function branches, Iff.mp and Iff.mpr apply an equivalence in each direction, Exists.intro t pf supplies a witness, and Exists.elim h f names the witness of an existential hypothesis. Each is a forward step, and a structured proof strings them together with have.
The commutativity of conjunction, proved backwards in Lecture 4, reads forwards as three have steps.
namespace Forward
theorem And_swap (a b : Prop) : a ∧ b → b ∧ a :=
assume h : a ∧ b;
have ha : a := And.left h;
have hb : b := And.right h;
show b ∧ a from And.intro hb ha
end Forward
The commutativity of disjunction consumes the hypothesis with Or.elim and rebuilds it on the other side. modus_ponens and Not_Not_intro combine the steps seen so far, recalling that ¬ a is a → False.
namespace Forward
theorem Or_swap (a b : Prop) : a ∨ b → b ∨ a :=
assume h : a ∨ b;
Or.elim h
(fun ha => Or.inr ha)
(fun hb => Or.inl hb)
theorem modus_ponens (a b : Prop) :
(a → b) → a → b :=
assume hab : a → b;
assume ha : a;
show b from hab ha
theorem Not_Not_intro (a : Prop) : a → ¬¬ a :=
assume ha : a;
assume hna : ¬ a;
show False from hna ha
end Forward
The high point of the section is the pair of one-point rules, which collapse a quantifier whose bound variable is pinned to a fixed value by an equation. The rule for ∀ says that a universally quantified implication guarded by x = t is equivalent to its instance at t; the rule for ∃ is its existential mirror. Each proof is structured, and each is more natural forwards than backwards.
namespace Forward
theorem Forall_one_point (α : Type) (t : α)
(P : α → Prop) :
(∀ x, x = t → P x) ↔ P t :=
Iff.intro
(assume h : ∀ x, x = t → P x; h t rfl)
(assume hpt : P t;
fix x : α; assume hxt : x = t; hxt ▸ hpt)
theorem Exists_one_point (α : Type) (t : α)
(P : α → Prop) :
(∃ x, x = t ∧ P x) ↔ P t :=
Iff.intro
(assume h : ∃ x, x = t ∧ P x;
Exists.elim h (fun x hx => hx.1 ▸ hx.2))
(assume hpt : P t;
Exists.intro t (And.intro rfl hpt))
end Forward
In the forward direction of the ∀ rule, the hypothesis is instantiated at t and the guard t = t is discharged by rfl. In the backward direction, an arbitrary x is fixed, the guard x = t is assumed, and the equation rewrites P t into P x through the substitution operator ▸. The ∃ rule supplies the witness t on one side and names the witness on the other.
5.3.1. Examples
The examples below apply each rule forwards by juxtaposition, then prove the two one-point rules.
Example 1. And.left and And.right extract the two conjuncts forwards.
namespace Forward
example (a b : Prop) (h : a ∧ b) : a :=
And.left h
example (a b : Prop) (h : a ∧ b) : b :=
And.right h
end Forward
Example 2. And.intro and the anonymous constructor build a conjunction, and the two terms are the same.
namespace Forward
example (a b : Prop) (ha : a) (hb : b) : a ∧ b :=
And.intro ha hb
example (a b : Prop) (ha : a) (hb : b) : a ∧ b :=
⟨ha, hb⟩
end Forward
Example 3. The commutativity of conjunction forwards, beside its Lecture 4 backward script.
namespace Forward
example (a b : Prop) : a ∧ b → b ∧ a :=
assume h : a ∧ b;
And.intro (And.right h) (And.left h)
example (a b : Prop) : a ∧ b → b ∧ a := a:Propb:Prop⊢ a ∧ b → b ∧ a
a:Propb:Proph:a ∧ b⊢ b ∧ a
a:Propb:Proph:a ∧ b⊢ ba:Propb:Proph:a ∧ b⊢ a
a:Propb:Proph:a ∧ b⊢ b All goals completed! 🐙
a:Propb:Proph:a ∧ b⊢ a All goals completed! 🐙
end Forward
Example 4. Or.inl and Or.inr build a disjunction by choosing a side.
namespace Forward
example (a b : Prop) (ha : a) : a ∨ b :=
Or.inl ha
example (a b : Prop) (hb : b) : a ∨ b :=
Or.inr hb
end Forward
Example 5. Or.elim h f g consumes a disjunction with two function branches.
namespace Forward
example (a b c : Prop) (h : a ∨ b) (f : a → c)
(g : b → c) : c :=
Or.elim h f g
end Forward
Example 6. Iff.mp and Iff.mpr apply an equivalence in each direction by juxtaposition.
namespace Forward
example (a b : Prop) (h : a ↔ b) (ha : a) : b :=
Iff.mp h ha
example (a b : Prop) (h : a ↔ b) (hb : b) : a :=
Iff.mpr h hb
end Forward
Example 7. Exists.intro t pf supplies a witness forwards, and the anonymous constructor is the same term.
namespace Forward
example (P : ℕ → Prop) (h : P 3) : ∃ n, P n :=
Exists.intro 3 h
example (P : ℕ → Prop) (h : P 3) : ∃ n, P n :=
⟨3, h⟩
end Forward
Example 8. Exists.elim h f names the witness of an existential hypothesis in a function branch.
namespace Forward
example (α : Type) (P : α → Prop) (Q : Prop)
(h : ∃ x, P x) (f : ∀ x, P x → Q) : Q :=
Exists.elim h f
end Forward
Example 9. The one-point rule for ∀ forwards, instantiating at t on one side and rewriting with the guard on the other.
namespace Forward
example (α : Type) (t : α) (P : α → Prop) :
(∀ x, x = t → P x) ↔ P t :=
Iff.intro
(assume h : ∀ x, x = t → P x; h t rfl)
(assume hpt : P t;
fix x : α; assume hxt : x = t; hxt ▸ hpt)
end Forward
Example 10. The one-point rule for ∃ forwards, contrasting the witness supplied on one side with the witness named on the other.
namespace Forward
example (α : Type) (t : α) (P : α → Prop) :
(∃ x, x = t ∧ P x) ↔ P t :=
Iff.intro
(assume h : ∃ x, x = t ∧ P x;
Exists.elim h (fun x hx => hx.1 ▸ hx.2))
(assume hpt : P t;
Exists.intro t (And.intro rfl hpt))
end Forward