Equality
module Chapter.Logic.Equality where
We have now all the necessary ingredients to understand how propositional equality is defined in Agda.
Imports
open import Library.Bool open import Library.Nat open import Library.List open import Library.Logic
Propositional equality
Propositional equality is nothing but an inductive family with an
implicit parameter A (the type of the terms being compared), a
parameter x (the leftmost term being compared) and an index (the
rightmost term being compared).
infix 4 _==_ data _==_ {A : Set} (x : A) : A -> Set where refl : x == x
As we can see from its definition, there is just one way of proving
an equality x == y, namely by using the constructor refl, which
imposes the two compared terms to be the same x. The name of this
constructor is intended to suggest that we are using the
reflexivity property of equality: every term is equal to
itself. In general, since Agda considers two terms to be “the same”
if they have the same normal form, we can use refl to construct
equality proofs for any two terms x and y that have the same
normal form. We have already seen a few examples of this when
proving properties of boolean values and when introducing
natural numbers.
_ : not true == false _ = refl _ : 1 + 2 == 3 _ = refl
Symmetry and transitivity
At first, it may be surprising that there are no ways of proving the
equality of two terms x and y other than reflexivity. After all,
we expect equality to be an equivalence relation, hence it should
also be symmetric and transitive. As it turns out, symmetry and
transitivity of equality can be proved as consequences of
reflexivity. Their proofs makes use of dot patterns, a feature
of Agda that we haven’t seen so far.
Let us start with symmetry. The property that we want to prove is stated as follows.
symm : ∀{A : Set} {x y : A} -> x == y -> y == x symm {_} {x} {y} eq = {!!}
For the sake of illustration, we have given names to the implicit
arguments x and y, whereas we have kept A unnamed as it plays
no interesting role in the proof. By inspecting the hole, we see
that we have to provide a proof of y == x in a context where we
have two elements x and y of type A and a term eq of type x
== y. Given the current situation, there isn’t much we can do
except realize that equality is an inductively defined data type. As
such, we can perform case analysis on eq.
symm₁ : ∀{A : Set} {x y : A} -> x == y -> y == x symm₁ {_} {x} {.x} refl = {!!}
As expected, the eq argument has turned into refl. However, case
analysis has also changed the pattern for the third implicit
argument y, which has turned into .x. This pattern means that
the third (implicit) argument of symm is not arbitrary, but it
must be the same as the second (implicit) argument x. The reason
is that the only way the constructor refl can be used as evidence
for the equality x == y is when x and y are the same (up to
Agda’s definitional equality).
This case analysis has another interesting effect on the context of
the hole that we are supposed to fill. By inspecting the hole we see
that the variable y is no longer present, since x and y have
been unified. As a consequence, the type of the hole has changed
from y == x to x == x. This means that we are now able to
complete the proof, since refl will provide evidence of the fact
that x is equal to itself.
symm₂ : ∀{A : Set} {x y : A} -> x == y -> y == x symm₂ {_} {x} {.x} refl = refl
The proof that equality is transitive follows a similar pattern.
trans : ∀{A : Set} {x y z : A} -> x == y -> y == z -> x == z trans eq1 eq2 = {!!}
By performing case analysis on eq1 and eq2 we effectively unify
the three (implicit) arguments x, y and z, so that we end up
with having to prove x == x, which can be done by reflexivity.
trans₁ : ∀{A : Set} {x y z : A} -> x == y -> y == z -> x == z trans₁ refl refl = refl
Congruence and substitution
In the chapter on natural numbers we have used the congruence
property of function application, namely the property that, if x ==
y, then f x == f y. We can now see how this theorem is proved.
cong : ∀{A B : Set} (f : A -> B) {x y : A} -> x == y -> f x == f y cong _ refl = refl
Once again we rely on case analysis to force the unification of x
and y, thereby turning congruence into another case of
reflexivity. Another principle related to equality is
substitution, asserting that if x == y and we know that x
satisfies some predicate P, then y also satisfies the same
predicate.
subst : ∀{A : Set} (P : A -> Set) {x y : A} -> x == y -> P x -> P y subst _ refl p = p
Equational reasoning
TODO
Homework
- Prove that
succis injective, namely the theoremsucc-injective : ∀{x y : ℕ} -> succ x == succ y -> x == y. - Define the relation
_!=_as the negation of equality. Prove thatzerois different from any other natural number, namely the theoremzero-succ : ∀{x : ℕ} -> zero != succ x - Prove the theorem
ne-ne : ∀{x y : ℕ} -> succ x != succ y -> x != y. - Prove that
_::_is injective, namely the theorem::-injective : ∀{A : Set} {x y : A} {xs ys : List A} -> x :: xs == y :: ys -> x == y ∧ xs == ys. - Prove a version of
congfor two-argument functions, namely the theoremcong2 : ∀{A B C : Set} (f : A -> B -> C) {x y : A} {u v : B} -> x == y -> u == v -> f x u == f y v
-- EXERCISE 1 succ-injective : ∀{x y : ℕ} -> succ x == succ y -> x == y succ-injective refl = refl -- EXERCISE 2 _!=_ : ∀{A : Set} -> A -> A -> Set x != y = ¬ (x == y) zero-succ : ∀{x : ℕ} -> zero != succ x zero-succ () -- EXERCISE 3 ne-ne : ∀{x y : ℕ} -> succ x != succ y -> x != y ne-ne neq refl = neq refl -- EXERCISE 4 ::-injective : ∀{A : Set} {x y : A} {xs ys : List A} -> x :: xs == y :: ys -> x == y ∧ xs == ys ::-injective refl = refl , refl -- EXERCISE 5 cong2 : ∀{A B C : Set} (f : A -> B -> C) {x y : A} {u v : B} -> x == y -> u == v -> f x u == f y v cong2 _ refl refl = refl