module Functions.Equality_Proofs where
open import Data.Nat using (ℕ; zero; suc; _≤_; z≤n; s≤s) open import Data.Nat using (ℕ; zero; suc; _+_; _*_; _≤_; z≤n; s≤s) open import Data.List using (List; []; _∷_; _++_) open import Data.Unit using (⊤; tt) open import Data.Product using (_×_; _,_) open import Function using (_$_) --
_≡_
Recall the definition of propositional equality:
data _≡_ {A : Set} (x : A) : A → Set where refl : x ≡ x infix 4 _≡_
yields
refl {ℕ} {0} : 0 ≡ 0
refl {ℕ} {1} : 1 ≡ 1
refl {ℕ} {2} : 2 ≡ 2
...
refl {Bool} {true} : true ≡ true
...
refl {Bool} {not b} : not b ≡ not b -- if 'b : Bool' is a parameter
...
_≡_
is an equivalence and a congruence_≡_
is an equivalence-relation:
refl' : ∀ {A} (a : A) → a ≡ a refl' a = refl sym : ∀ {A} {a b : A} → a ≡ b → b ≡ a sym refl = refl -- after pattern matching on 'refl', 'a' and 'b' coincides
Exercise
trans : ∀ {A} {a b c : A} → a ≡ b → b ≡ c → a ≡ c
Prove that every function is compatible with the equivalence relation (congruency):
cong : ∀ {A B} {m n : A} → (f : A → B) → m ≡ n → f m ≡ f n
Agda reduces types automatically during type checking.
This is safe because all functions terminate.
Example:
1 + 1 ≡ 2
⇓ 2 ≡ 2
.
Consequences:
refl : 1 + 1 ≡ 2
...
refl : 0 + n ≡ n -- if 'n : ℕ' is a parameter
...
x
and y
are definitionally equal iff refl : x ≡ y
.
"Definitional equality is trivial equality."
Example
1+1≡2 : 1 + 1 ≡ 2 1+1≡2 = refl
Counterexample
Suppose that n : ℕ
is a parameter.
refl : n + 0 ≡ 0 + n -- type error!
This doesn't typecheck becausen + 0 ≡ 0 + n
⇓ n + 0 ≡ n
and n + 0
is not the same as n
.
a + 0 ≡ a
+-right-identity : ∀ n → n + 0 ≡ n +-right-identity zero = refl +-right-identity (suc n) = cong suc (+-right-identity n)
So n + 0 ≡ n
is not trivial,
but for any n
we can construct the proof of it.
This is a bit funny though:
+-right-identity 0 ⇓ refl
+-right-identity 1 ⇓ refl
+-right-identity 2 ⇓ refl
...
So the code of +-right-identity
is kind of dead code (doesn't do anything meaningful at run time).
We'll discuss this later.
Finish the ingredients of the proof that (ℕ
, _+_
) is a commutative monoid!
+-left-identity : ∀ a → 0 + a ≡ a
+-assoc : ∀ a b c → a + (b + c) ≡ (a + b) + c -- hint: use cong
For commutativity you need a helper function first:
m+1+n≡1+m+n : ∀ m n → m + suc n ≡ suc (m + n)
List ⊤
~ ℕ
Let
fromList : List ⊤ → ℕ fromList [] = zero fromList (x ∷ xs) = suc (fromList xs) toList : ℕ → List ⊤ toList zero = [] toList (suc n) = tt ∷ toList n
Let's prove that fromList
and toList
are inverses of each other and that they preserve the operations _++_
and _+_
!
from-to : ∀ a → fromList (toList a) ≡ a
to-from : ∀ a → toList (fromList a) ≡ a
fromPreserves++ : ∀ (a b : List ⊤) → fromList (a ++ b) ≡ fromList a + fromList b
toPreserves+ : ∀ (a b : ℕ) → toList (a + b) ≡ toList a ++ toList b
Equational reasoning is not a new language construct!
_≡⟨_⟩_ : ∀ {A : Set} (x : A) {y z : A} → x ≡ y → y ≡ z → x ≡ z x ≡⟨ refl ⟩ refl = refl infixr 2 _≡⟨_⟩_ _∎ : ∀ {A : Set} (x : A) → x ≡ x x ∎ = refl infix 2 _∎
Usage example:
+-comm' : (n m : ℕ) → n + m ≡ m + n +-comm' zero n = sym (+-right-identity n) +-comm' (suc m) n = suc m + n ≡⟨ refl ⟩ suc (m + n) ≡⟨ cong suc (+-comm' m n) ⟩ suc (n + m) ≡⟨ sym (m+1+n≡1+m+n n m) ⟩ n + suc m ∎
_*_
We'd like to prove that (ℕ
, _*_
) is a commutative monoid.
We will need distributivity:
distribʳ-*-+ : ∀ a b c → (a + b) * c ≡ a * c + b * c distribʳ-*-+ zero b c = refl distribʳ-*-+ (suc a) b c = c + (a + b) * c ≡⟨ cong (λ x → c + x) (distribʳ-*-+ a b c) ⟩ c + (a * c + b * c) ≡⟨ +-assoc c (a * c) (b * c) ⟩ c + a * c + b * c ∎
Define the following functions:
*-assoc : ∀ a b c → a * (b * c) ≡ (a * b) * c
*-left-identity : ∀ a → 1 * a ≡ a
*-right-identity : ∀ a → a * 1 ≡ a
Commutativity:
-- helper functions: n*0≡0 : ∀ n → n * 0 ≡ 0
*-suc : ∀ n m → n + n * m ≡ n * suc m
*-comm : ∀ m n → m * n ≡ n * m
module trySemiringSolver where open import Data.Nat open import Data.Nat.Properties open SemiringSolver open import Relation.Binary.PropositionalEquality renaming (_≡_ to _≡-official_) f : ∀ a b c → a + b * c + 1 ≡-official 1 + c * b + a f = solve 3 (λ a b c → a :+ b :* c :+ con 1 := con 1 :+ c :* b :+ a) refl