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