Equational Reasoning
This module provides syntax for equational reasoning with different relations. Instead of writing nested function applications, you can write chain-of-reasoning proofs that read like mathematical prose.
For Equivalence Relations
Given an equivalence relation ∼, you can write:
begin
a ∼⟨ proof-a∼b ⟩
b ∼⟨ proof-b∼c ⟩
c ∎
Instead of: transitive proof-a∼b proof-b∼c
For Preorder Relations
Given a preorder ≤, you can write:
begin
x ≤⟨ proof-x≤y ⟩
y ≤⟨ proof-y≤z ⟩
z ∎
Instead of: transitive proof-x≤y proof-y≤z
module plumbing.EquationalReasoning where open import Relation.Binary.PropositionalEquality using (_≡_)
Reasoning for Equivalence Relations
module ∼-Reasoning {A : Set} (_∼_ : A → A → Set) (reflexive : ∀ {x} → x ∼ x) (symmetric : ∀ {x y} → x ∼ y → y ∼ x) (transitive : ∀ {x y z} → x ∼ y → y ∼ z → x ∼ z) where infix 3 _∎ infixr 2 _∼⟨_⟩_ _≈⟨_⟩_ infix 1 begin_ -- Start a reasoning chain begin_ : ∀ {x y} → x ∼ y → x ∼ y begin p = p -- Step forward: x ∼ y and y ∼ z implies x ∼ z _∼⟨_⟩_ : ∀ x {y z} → x ∼ y → y ∼ z → x ∼ z x ∼⟨ p ⟩ q = transitive p q -- Alternative syntax with ≈ symbol (same as ∼) _≈⟨_⟩_ : ∀ x {y z} → x ∼ y → y ∼ z → x ∼ z x ≈⟨ p ⟩ q = transitive p q -- End a reasoning chain _∎ : ∀ x → x ∼ x x ∎ = reflexive -- Backward step: x ∼ y follows from y ∼ x by symmetry _∼˘⟨_⟩_ : ∀ x {y z} → y ∼ x → y ∼ z → x ∼ z x ∼˘⟨ p ⟩ q = transitive (symmetric p) q
Reasoning for Preorder Relations
module ≤-Reasoning {A : Set} (_≤_ : A → A → Set) (reflexive : ∀ {x} → x ≤ x) (transitive : ∀ {x y z} → x ≤ y → y ≤ z → x ≤ z) where infix 3 _∎ infixr 2 _≤⟨_⟩_ infix 1 begin_ -- Start a reasoning chain begin_ : ∀ {x y} → x ≤ y → x ≤ y begin p = p -- Step forward: x ≤ y and y ≤ z implies x ≤ z _≤⟨_⟩_ : ∀ x {y z} → x ≤ y → y ≤ z → x ≤ z x ≤⟨ p ⟩ q = transitive p q -- End a reasoning chain _∎ : ∀ x → x ≤ x x ∎ = reflexive
Reasoning for Propositional Equality
For completeness, we also provide reasoning for ≡ (though Agda’s standard library has this).
module ≡-Reasoning where open import Relation.Binary.PropositionalEquality using (trans; sym; refl) infix 3 _∎ infixr 2 _≡⟨_⟩_ _≡˘⟨_⟩_ infix 1 begin_ -- Start a reasoning chain begin_ : ∀ {A : Set} {x y : A} → x ≡ y → x ≡ y begin p = p -- Step forward: x ≡ y and y ≡ z implies x ≡ z _≡⟨_⟩_ : ∀ {A : Set} (x : A) {y z : A} → x ≡ y → y ≡ z → x ≡ z x ≡⟨ p ⟩ q = trans p q -- Backward step: x ≡ y follows from y ≡ x by symmetry _≡˘⟨_⟩_ : ∀ {A : Set} (x : A) {y z : A} → y ≡ x → y ≡ z → x ≡ z x ≡˘⟨ p ⟩ q = trans (sym p) q -- End a reasoning chain _∎ : ∀ {A : Set} (x : A) → x ≡ x x ∎ = refl
Examples
Here are some example usages:
module Examples where open import definitions.chapter1.EquivalenceRelation using (IsEquivalence) open import definitions.chapter1.Relation using (BinRel) -- Example: Using ∼-Reasoning module EquivExample {A : Set} (_∼_ : BinRel A) (equiv : IsEquivalence _∼_) where open IsEquivalence equiv open ∼-Reasoning _∼_ reflexive symmetric transitive -- Instead of: transitive (transitive a∼b b∼c) c∼d -- We can write: example : ∀ {a b c d} → a ∼ b → b ∼ c → c ∼ d → a ∼ d example {a} {b} {c} {d} a∼b b∼c c∼d = begin a ∼⟨ a∼b ⟩ b ∼⟨ b∼c ⟩ c ∼⟨ c∼d ⟩ d ∎ -- Example: Using ≡-Reasoning module EqualityExample where open ≡-Reasoning example : ∀ {A : Set} {a b c : A} → a ≡ b → b ≡ c → a ≡ c example {a = a} {b} {c} a≡b b≡c = begin a ≡⟨ a≡b ⟩ b ≡⟨ b≡c ⟩ c ∎