5.4. Calculational Proofs
A calculational proof lays a chain of equalities out for the reader, one step per line, each step justified by a rewrite or a lemma. The keyword calc composes the steps into a single transitive derivation, playing the part of Eq.trans so the writer does not have to. Each step is exactly the kind of equation that rw consumes, and a step that holds only up to associativity and commutativity is closed by the ac_rfl of Lecture 4. The layout reads as a mathematician writes it, with the running term on the left and the justification on the right.
namespace Forward
theorem two_mul_example (m n : ℕ) :
2 * m + n = m + n + m := m:ℕn:ℕ⊢ 2 * m + n = m + n + m
calc 2 * m + n = (m + m) + n := m:ℕn:ℕ⊢ 2 * m + n = m + m + n All goals completed! 🐙
_ = m + n + m := by m:ℕn:ℕ⊢ m + m + n = m + n + m ac_rfl All goals completed! 🐙
end Forward
The same argument written with nested have steps and Eq.trans shows what calc abbreviates. The chain of two equalities becomes two named facts joined by transitivity.
namespace Forward
theorem two_mul_example_have (m n : ℕ) :
2 * m + n = m + n + m := by m:ℕn:ℕ⊢ 2 * m + n = m + n + m
have h1 : 2 * m + n = (m + m) + n := by
rw [Nat.two_mul m:ℕn:ℕ⊢ m + m + n = m + m + n] m:ℕn:ℕh1:2 * m + n = m + m + n⊢ 2 * m + n = m + n + m
have h2 : (m + m) + n = m + n + m := by ac_rfl m:ℕn:ℕh1:2 * m + n = m + m + nh2:m + m + n = m + n + m⊢ 2 * m + n = m + n + m
exact Eq.trans h1 h2 All goals completed! 🐙
end Forward
calc also chains any transitive relation, not equality alone, and the examples include a chain over ↔ closed by Iff.trans.
5.4.1. Examples
The examples below build calculational chains, justify their steps by rewrites and by lemmas, and compare calc with the alternatives it abbreviates.
Example 1. A two-step chain on ℕ, each step closed by rfl.
namespace Forward
example : (1 : ℕ) + 1 + 1 = 3 := by ⊢ 1 + 1 + 1 = 3
calc (1 : ℕ) + 1 + 1 = 2 + 1 := rfl
_ = 3 := rfl
end Forward
Example 2. The same identity by Eq.trans, which exposes what the chain abbreviates.
namespace Forward
example : (1 : ℕ) + 1 + 1 = 3 :=
Eq.trans
(rfl : (1 : ℕ) + 1 + 1 = 2 + 1)
(rfl : (2 : ℕ) + 1 = 3)
end Forward
Example 3. A single step justified by rewriting with commutativity.
namespace Forward
example (a b : ℕ) : a + b = b + a := by a:ℕb:ℕ⊢ a + b = b + a
calc a + b = b + a := by a:ℕb:ℕ⊢ a + b = b + a rw [Nat.add_comm a:ℕb:ℕ⊢ b + a = b + a] All goals completed! 🐙
end Forward
Example 4. A step justified by a named lemma from Lecture 4, the associativity of our add.
namespace Forward
example (l m n : ℕ) :
add (add l m) n = add l (add m n) := by l:ℕm:ℕn:ℕ⊢ add (add l m) n = add l (add m n)
calc add (add l m) n
= add l (add m n) := Backward.add_assoc l m n
end Forward
Example 5. A chain that mixes a rw step with an ac_rfl step, the full doubling identity.
namespace Forward
example (m n : ℕ) : 2 * m + n = m + n + m := by m:ℕn:ℕ⊢ 2 * m + n = m + n + m
calc 2 * m + n = (m + m) + n := by m:ℕn:ℕ⊢ 2 * m + n = m + m + n rw [Nat.two_mul m:ℕn:ℕ⊢ m + m + n = m + m + n] All goals completed! 🐙
_ = m + n + m := by m:ℕn:ℕ⊢ m + m + n = m + n + m ac_rfl All goals completed! 🐙
end Forward
Example 6. A chain whose last step is ac_rfl and whose first is a rfl.
namespace Forward
example (a b c : ℕ) : a + b + c = c + (a + b) := by a:ℕb:ℕc:ℕ⊢ a + b + c = c + (a + b)
calc a + b + c = (a + b) + c := rfl
_ = c + (a + b) := by a:ℕb:ℕc:ℕ⊢ a + b + c = c + (a + b) ac_rfl All goals completed! 🐙
end Forward
Example 7. A chain of three equalities built from two hypotheses.
namespace Forward
example (a b c d : ℕ) (h1 : a = b) (h2 : b = c)
(h3 : c = d) : a = d := by a:ℕb:ℕc:ℕd:ℕh1:a = bh2:b = ch3:c = d⊢ a = d
calc a = b := h1
_ = c := h2
_ = d := h3
end Forward
Example 8. calc chains two biconditionals with Iff.trans exactly as it chains equalities.
namespace Forward
example (a b c : Prop) (h1 : a ↔ b) (h2 : b ↔ c) :
a ↔ c := by a:Propb:Propc:Proph1:a ↔ bh2:b ↔ c⊢ a ↔ c
calc a ↔ b := h1
_ ↔ c := h2
end Forward
Example 9. The same goal by an explicit chain and by a single simp, which shows when the chain earns its length.
namespace Forward
example (a b : ℕ) : (a + b) * 1 = a + b := by a:ℕb:ℕ⊢ (a + b) * 1 = a + b
calc (a + b) * 1 = a + b := by a:ℕb:ℕ⊢ (a + b) * 1 = a + b rw [Nat.mul_one a:ℕb:ℕ⊢ a + b = a + b] All goals completed! 🐙
example (a b : ℕ) : (a + b) * 1 = a + b := by a:ℕb:ℕ⊢ (a + b) * 1 = a + b
simp All goals completed! 🐙
end Forward
Example 10. A step that reads right to left, justified by a rewrite with a reversed equation.
namespace Forward
example (a b : ℕ) (h : a = b) : b = a := by a:ℕb:ℕh:a = b⊢ b = a
calc b = a := by a:ℕb:ℕh:a = b⊢ b = a rw [← h a:ℕb:ℕh:a = b⊢ a = a] All goals completed! 🐙
end Forward