------------------------------------------------------------------------
-- The Agda standard library
--
-- Documentation for pointwise equality over `List`s
------------------------------------------------------------------------

{-# OPTIONS --allow-unsolved-metas #-}

module README.Data.List.Relation.Binary.Equality where

open import Data.Nat using (ℕ; _+_; _<_; s≤s; z≤n; _*_; _∸_; _≤_)
open import Data.Nat.Properties as ℕ
open import Data.List.Base

------------------------------------------------------------------------
-- Pointwise equality

-- There are many different options for what it means for two
-- different lists of type `List A` to be "equal". Here we will
-- consider "pointwise" equality that requires the lists to be the
-- same length and every pair of elements to be "equal".

-- The most basic option is simply to use propositional equality
-- `_≡_` over lists:

open import Relation.Binary.PropositionalEquality
  using (_≡_; sym; refl)

lem₁ : 1 ∷ 2 ∷ 3 ∷ [] ≡ 1 ∷ 2 ∷ 3 ∷ []
lem₁ = refl

-- However propositional equality is only suitable when we want to
-- use propositional equality to compare the individual elements.
-- Although a contrived example, consider trying to prove the
-- equality of two lists of the type `List (ℕ → ℕ)`:

lem₂ : (λ x → 2 * x + 2) ∷ [] ≡ (λ x → 2 * (x + 1)) ∷ []
lem₂ = {!!}

-- In such a case it is impossible to prove the two lists equal with
-- refl as the two functions are not propositionally equal. In the
-- absence of postulating function extensionality (see README.Axioms),
-- the most common definition of function equality is to say that two
-- functions are equal if their outputs are always propositionally
-- equal for any input. This notion of function equality `_≗_` is
-- found in:

open import Relation.Binary.PropositionalEquality using (_≗_)

-- We now want to use the `Pointwise` relation to say that the two
-- lists are equal if their elements are pointwise equal with resepct
-- to `_≗_`. However instead of using the pointwise module directly
-- to write:

open import Data.List.Relation.Binary.Pointwise.Base using (Pointwise)

lem₃ : Pointwise _≗_ ((λ x → x + 1) ∷ []) ((λ x → x + 2 ∸ 1) ∷ [])
lem₃ = {!!}

-- the library provides some nicer wrappers and infix notation in the
-- folder "Data.List.Relation.Binary.Equality".

-- Within this folder there are four different modules.

import Data.List.Relation.Binary.Equality.Setoid           as SetoidEq
import Data.List.Relation.Binary.Equality.DecSetoid        as DecSetoidEq
import Data.List.Relation.Binary.Equality.Propositional    as PropEq
import Data.List.Relation.Binary.Equality.DecPropositional as DecPropEq

-- Which one should be used depends on whether the underlying equality
-- over "A" is:
--   i)  propositional or setoid-based
--   ii) decidable.

-- Each of the modules except `PropEq` are designed to be opened with a
-- module parameter. This is to avoid having to specify the underlying
-- equality relation or the decidability proofs every time you use the
-- list equality.

-- In our example function equality is not decidable and not propositional
-- and so we want to use the `SetoidEq` module. This requires a proof that
-- the `_≗_` relation forms a setoid over functions of the type `ℕ → ℕ`.
-- This is found in:

open import Relation.Binary.PropositionalEquality using (_→-setoid_)

-- The `SetoidEq` module should therefore be opened as follows:

open SetoidEq (ℕ →-setoid ℕ)

-- All four equality modules provide an infix operator `_≋_` for the
-- new equality relation over lists. The type of `lem₃` can therefore
-- be rewritten as:

lem₄ : (λ x → x + 1) ∷ [] ≋ (λ x → x + 2 ∸ 1) ∷ []
lem₄ = 2x+2≗2[x+1] ∷ []
  where
  2x+2≗2[x+1] : (λ x → x + 1) ≗ (λ x → x + 2 ∸ 1)
  2x+2≗2[x+1] x = sym (+-∸-assoc x (s≤s z≤n))

-- The modules also provide proofs that the `_≋_` relation is a
-- setoid in its own right and therefore is reflexive, symmetric,
-- transitive:

lem₅ : (λ x → 2 * x + 2) ∷ [] ≋ (λ x → 2 * x + 2) ∷ []
lem₅ = ≋-refl

-- If we could prove that `_≗_` forms a `DecSetoid` then we could use
-- the module `DecSetoidEq` instead. This exports everything from
-- `SetoidEq` as well as the additional proof `_≋?_` that the list
-- equality is decidable.

-- This pattern of four modules for each of the four different types
-- of equality is repeated throughout the library (e.g. see the
-- `Membership`). Note that in this case the modules `PropEq` and
-- `DecPropEq` are not very useful as if two lists are pointwise
-- propositionally equal they are necessarily propositionally equal
-- (and vice-versa). There are proofs of this fact exported by
-- `PropEq` and `DecPropEq`. Although, these two types of list equality
-- are not very useful in practice, they are included for completeness's
-- sake.
