Martin Escardo, 5th April 2024
Demonstration of `remove` and `remove-swap` without Agda's `with`,
regarding a mastodon discussion.
https://mathstodon.xyz/deck/@MartinEscardo/112214064298894127
We use Hedberg to show that any two proofs of equality are themselves
equal, in a discrete type. This is because we want to disable K.
We use function extensionality to show that any two proofs of negation
of equality are themselves equal.
*Challenge* Re-define `remove-swap` below
* without Hedberg,
* Without function extensionality,
* without Agda's `with`,
and still with `--safe` and `--without-K` and all other flags in
typetopology.agda-lib.
(This file is extracted from a larger file about this subject, to be
published in the TypeTopology in the near future.)
\begin{code}
{-# OPTIONS --safe --without-K #-}
open import MLTT.Spartan
open import UF.FunExt
open import UF.DiscreteAndSeparated
module gist.remove-swap
(fe : Fun-Ext)
{𝓤 : Universe}
(X : 𝓤 ̇ )
(d : is-discrete X)
where
open import MLTT.List
\end{code}
We first define a conditional `cons` operation, and then we use it to
define `remove`.
\begin{code}
abstract
ccons : ({x} y : X) → is-decidable (x = y) → List X → List X
ccons y (inl e) ys = ys
ccons y (inr u) ys = y ∷ ys
remove : X → List X → List X
remove x [] = []
remove x (y ∷ ys) = ccons y (d x y) (remove x ys)
\end{code}
The following two facts are the specification of `remove`. (See below
for discussion and more verbose proofs that are much clearer.)
\begin{code}
module _ (x y : X) (zs : List X) where
abstract
remove-= : x = y → remove x (y ∷ zs) = remove x zs
remove-= e = ap (λ - → ccons y - (remove x zs)) (discrete-inl d x y e)
remove-≠ : x ≠ y → remove x (y ∷ zs) = y ∷ remove x zs
remove-≠ u = ap (λ - → ccons y - (remove x zs)) (discrete-inr fe d x y u)
\end{code}
A particular case of `remove-=` occurs more often in practice.
\begin{code}
remove-same : (x : X) (ys : List X) → remove x (x ∷ ys) = remove x ys
remove-same x ys = remove-= x x ys refl
\end{code}
And this is our definition of `remove-swap` without `with`. Notice
that the helper function h plays the role of `with`.
\begin{code}
remove-swap : (x y : X) (zs : List X)
→ remove x (remove y zs) = remove y (remove x zs)
remove-swap x y [] = refl
remove-swap x y (z ∷ zs) = h (d x z) (d y z)
where
IH : remove x (remove y zs) = remove y (remove x zs)
IH = remove-swap x y zs
h : is-decidable (x = z)
→ is-decidable (y = z)
→ remove x (remove y (z ∷ zs)) = remove y (remove x (z ∷ zs))
h (inl refl) (inl refl) = refl
h (inl refl) (inr v) =
remove x (remove y (x ∷ zs)) =⟨ ap (remove x) (remove-≠ y x zs v) ⟩
remove x (x ∷ remove y zs) =⟨ remove-same x (remove y zs) ⟩
remove x (remove y zs) =⟨ IH ⟩
remove y (remove x zs) =⟨ ap (remove y) ((remove-same x zs)⁻¹) ⟩
remove y (remove x (x ∷ zs)) ∎
h (inr u) (inl refl) =
remove x (remove y (y ∷ zs)) =⟨ ap (remove x) (remove-same y zs) ⟩
remove x (remove y zs) =⟨ IH ⟩
remove y (remove x zs) =⟨ (remove-same y (remove x zs))⁻¹ ⟩
remove y (y ∷ remove x zs) =⟨ ap (remove y) (remove-≠ x y zs u)⁻¹ ⟩
remove y (remove x (y ∷ zs)) ∎
h (inr u) (inr v) =
remove x (remove y (z ∷ zs)) =⟨ ap (remove x) (remove-≠ y z zs v) ⟩
remove x (z ∷ remove y zs) =⟨ remove-≠ x z (remove y zs) u ⟩
z ∷ remove x (remove y zs) =⟨ ap (z ∷_) IH ⟩
z ∷ remove y (remove x zs) =⟨ (remove-≠ y z (remove x zs) v)⁻¹ ⟩
remove y (z ∷ remove x zs) =⟨ (ap (remove y) (remove-≠ x z zs u))⁻¹ ⟩
remove y (remove x (z ∷ zs)) ∎
\end{code}
I think it's better to be verbose, and this is what we tend to do in
TypeTopology, because we want people to understand what's going on by
reading the code, as much as possible.
The first of the following two proofs use Hedberg (to show that d x y
= inl e), and the second one uses Herberg and, and additionally
function extensionality (to show that d x y = inr u). This is the only
place function extensionality is used in this file. Also notice that
we only use function extensionality for empty-type-valued functions!
\begin{code}
module _ (x y : X) (zs : List X) where
abstract
verbose-remove-= : x = y → remove x (y ∷ zs) = remove x zs
verbose-remove-= e =
remove x (y ∷ zs) =⟨ refl ⟩
ccons y (d x y) (remove x zs) =⟨ ap (λ - → ccons y - (remove x zs)) I ⟩
ccons y (inl e) (remove x zs) =⟨ refl ⟩
remove x zs ∎
where
I : d x y = inl e
I = discrete-inl d x y e
verbose-remove-≠ : x ≠ y → remove x (y ∷ zs) = y ∷ remove x zs
verbose-remove-≠ u =
remove x (y ∷ zs) =⟨ refl ⟩
ccons y (d x y) (remove x zs) =⟨ ap (λ - → ccons y - (remove x zs)) I ⟩
ccons y (inr u) (remove x zs) =⟨ refl ⟩
y ∷ remove x zs ∎
where
I : d x y = inr u
I = discrete-inr fe d x y u
\end{code}