Martin Escardo.
Formulation of function extensionality. Notice that this file doesn't
postulate function extensionality. It only defines the concept, which
is used explicitly as a hypothesis each time it is needed.
\begin{code}
{-# OPTIONS --safe --without-K #-}
module UF.FunExt where
open import MLTT.Spartan
open import UF.Base
open import UF.Equiv
open import UF.LeftCancellable
\end{code}
The appropriate notion of function extensionality in univalent
mathematics is funext, define below. It is implied, by an argument due
to Voevodky, by naive, non-dependent function extensionality, written
naive-funext here.
\begin{code}
naive-funext : ∀ 𝓤 𝓥 → 𝓤 ⁺ ⊔ 𝓥 ⁺ ̇
naive-funext 𝓤 𝓥 = {X : 𝓤 ̇ } {Y : 𝓥 ̇ } {f g : X → Y} → f ∼ g → f = g
DN-funext : ∀ 𝓤 𝓥 → 𝓤 ⁺ ⊔ 𝓥 ⁺ ̇
DN-funext 𝓤 𝓥 = {X : 𝓤 ̇ } {A : X → 𝓥 ̇ } {f g : Π A} → f ∼ g → f = g
funext : ∀ 𝓤 𝓥 → 𝓤 ⁺ ⊔ 𝓥 ⁺ ̇
funext 𝓤 𝓥 = {X : 𝓤 ̇ } {A : X → 𝓥 ̇ } (f g : Π A) → is-equiv (happly' f g)
funext₀ : 𝓤₁ ̇
funext₀ = funext 𝓤₀ 𝓤₀
FunExt : 𝓤ω
FunExt = (𝓤 𝓥 : Universe) → funext 𝓤 𝓥
Fun-Ext : 𝓤ω
Fun-Ext = {𝓤 𝓥 : Universe} → funext 𝓤 𝓥
≃-funext : funext 𝓤 𝓥 → {X : 𝓤 ̇ } {A : X → 𝓥 ̇ } (f g : Π A)
→ (f = g) ≃ (f ∼ g)
≃-funext fe f g = happly' f g , fe f g
abstract
dfunext : funext 𝓤 𝓥 → DN-funext 𝓤 𝓥
dfunext fe {X} {A} {f} {g} = inverse (happly' f g) (fe f g)
happly-funext : {X : 𝓤 ̇ } {A : X → 𝓥 ̇ }
(fe : funext 𝓤 𝓥) (f g : Π A) (h : f ∼ g)
→ happly (dfunext fe h) = h
happly-funext fe f g = inverses-are-sections happly (fe f g)
funext-happly : {X : 𝓤 ̇ } {A : X → 𝓥 ̇ } (fe : funext 𝓤 𝓥)
→ (f g : Π A) (h : f = g)
→ dfunext fe (happly h) = h
funext-happly fe f g refl = inverses-are-retractions happly (fe f f) refl
happly-≃ : {X : 𝓤 ̇ } {A : X → 𝓥 ̇ }
(fe : funext 𝓤 𝓥)
{f g : (x : X) → A x}
→ (f = g) ≃ f ∼ g
happly-≃ fe = happly , fe _ _
funext-lc : {X : 𝓤 ̇ } {A : X → 𝓥 ̇ }
(fe : funext 𝓤 𝓥)
(f g : Π A)
→ left-cancellable (dfunext fe {X} {A} {f} {g})
funext-lc fe f g = section-lc (dfunext fe) (happly , happly-funext fe f g)
happly-lc : {X : 𝓤 ̇ } {A : X → 𝓥 ̇ }
(fe : funext 𝓤 𝓥)
(f g : Π A)
→ left-cancellable (happly' f g)
happly-lc fe f g = section-lc happly (equivs-are-sections happly (fe f g))
inverse-of-happly-is-dfunext : {A : 𝓤 ̇ } {B : 𝓥 ̇ }
(fe₀ : funext 𝓤 𝓥)
(fe₁ : funext (𝓤 ⊔ 𝓥) (𝓤 ⊔ 𝓥))
(f g : A → B)
→ inverse (happly' f g) (fe₀ f g) = dfunext fe₀
inverse-of-happly-is-dfunext fe₀ fe₁ f g =
dfunext fe₁
(λ h → happly-lc fe₀ f g
(happly' f g (inverse (happly' f g) (fe₀ f g) h)
=⟨ inverses-are-sections _ (fe₀ f g) h ⟩
h =⟨ happly-funext fe₀ f g h ⁻¹ ⟩
happly' f g (dfunext fe₀ h) ∎))
dfunext-refl : {X : 𝓤 ̇ } {A : X → 𝓥 ̇ }
(fe : funext 𝓤 𝓥)
(f : Π A)
→ dfunext fe (λ (x : X) → 𝓻𝓮𝒻𝓵 (f x)) = refl
dfunext-refl fe f = happly-lc fe f f (happly-funext fe f f (λ x → refl))
ap-funext : {X : 𝓥 ̇ } {Y : 𝓦 ̇ }
(f g : X → Y)
{A : 𝓦' ̇ } (k : Y → A)
(h : f ∼ g)
(fe : funext 𝓥 𝓦) (x : X)
→ ap (λ (- : X → Y) → k (- x)) (dfunext fe h) = ap k (h x)
ap-funext f g k h fe x = ap (λ - → k (- x)) (dfunext fe h) =⟨ refl ⟩
ap (k ∘ (λ - → - x)) (dfunext fe h) =⟨ I ⟩
ap k (ap (λ - → - x) (dfunext fe h)) =⟨ refl ⟩
ap k (happly (dfunext fe h) x) =⟨ II ⟩
ap k (h x) ∎
where
I = (ap-ap (λ - → - x) k (dfunext fe h))⁻¹
II = ap (λ - → ap k (- x)) (happly-funext fe f g h)
ap-precomp-funext : {X : 𝓤 ̇ } {Y : 𝓥 ̇ } {A : 𝓦 ̇ }
(f g : X → Y)
(k : A → X) (h : f ∼ g)
(fe₀ : funext 𝓤 𝓥)
(fe₁ : funext 𝓦 𝓥)
→ ap (_∘ k) (dfunext fe₀ h) = dfunext fe₁ (h ∘ k)
ap-precomp-funext f g k h fe₀ fe₁ =
ap (_∘ k) (dfunext fe₀ h) =⟨ I ⟩
dfunext fe₁ (happly (ap (_∘ k) (dfunext fe₀ h))) =⟨ II ⟩
dfunext fe₁ (h ∘ k) ∎
where
I = funext-happly fe₁ (f ∘ k) (g ∘ k) _ ⁻¹
III = λ x →
ap (λ - → - x) (ap (_∘ k) (dfunext fe₀ h)) =⟨ ap-ap _ _ (dfunext fe₀ h) ⟩
ap (λ - → - (k x)) (dfunext fe₀ h) =⟨ ap-funext f g id h fe₀ (k x) ⟩
ap (λ v → v) (h (k x)) =⟨ ap-id-is-id (h (k x)) ⟩
h (k x) ∎
II = ap (dfunext fe₁) (dfunext fe₁ III)
\end{code}
The following is taken from this thread:
https://groups.google.com/forum/#!msg/homotopytypetheory/VaLJM7S4d18/Lezr_ZhJl6UJ
\begin{code}
transport-funext : {X : 𝓤 ̇ } (A : X → 𝓥 ̇ )
(P : (x : X) → A x → 𝓦 ̇ )
(fe : funext 𝓤 𝓥)
(f g : Π A)
(φ : (x : X) → P x (f x))
(h : f ∼ g)
(x : X)
→ transport (λ - → (x : X) → P x (- x)) (dfunext fe h) φ x
= transport (P x) (h x) (φ x)
transport-funext A P fe f g φ h x =
transport (λ - → ∀ x → P x (- x)) (dfunext fe h) φ x =⟨ I ⟩
transport (P x) (happly (dfunext fe h) x) (φ x) =⟨ II ⟩
transport (P x) (h x) (φ x) ∎
where
lemma : (f g : Π A) (φ : ∀ x → P x (f x)) (p : f = g)
→ ∀ x → transport (λ - → ∀ x → P x (- x)) p φ x
= transport (P x) (happly p x) (φ x)
lemma f f φ refl x = refl
I = lemma f g φ (dfunext fe h) x
II = ap (λ - → transport (P x) (- x) (φ x)) (happly-funext fe f g h)
transport-funext' : {X : 𝓤 ̇ } (A : 𝓥 ̇ )
(P : X → A → 𝓦 ̇ )
(fe : funext 𝓤 𝓥)
(f g : X → A)
(φ : (x : X) → P x (f x))
(h : f ∼ g)
(x : X)
→ transport (λ - → (x : X) → P x (- x)) (dfunext fe h) φ x
= transport (P x) (h x) (φ x)
transport-funext' A P = transport-funext (λ _ → A) P
\end{code}
Added 22nd October 2024. Implicit DN-funext.
\begin{code}
Πᵢ : {X : 𝓤 ̇ } (A : X → 𝓥 ̇ ) → 𝓤 ⊔ 𝓥 ̇
Πᵢ {𝓤} {𝓥} {X} A = {x : X} → A x
module _ {X : 𝓤 ̇ } {A : X → 𝓥 ̇ } where
infix 4 _∼ᵢ_
_∼ᵢ_ : Πᵢ A → Πᵢ A → 𝓤 ⊔ 𝓥 ̇
f ∼ᵢ g = ∀ x → f {x} = g {x}
explicit : Πᵢ A → Π A
explicit f x = f {x}
implicit : Π A → Πᵢ A
implicit f {x} = f x
∼ᵢ-gives-∼ : (f g : Πᵢ A) → f ∼ᵢ g → explicit f ∼ explicit g
∼ᵢ-gives-∼ f g h x = h x
∼-gives-∼ᵢ : (f g : Π A) → f ∼ g → implicit f ∼ᵢ implicit g
∼-gives-∼ᵢ f g h x = h x
implicit-η-rule : (f : Πᵢ A) → (λ {x} → f {x}) = f
implicit-η-rule f = refl
\end{code}
Agda gets confused when we try to write f = g for f g : Πᵢ A, because
it thinks that an implicit argument is implicitly applied to f and g,
but then it is not able to infer it. To prevent this from happening,
can write (λ {x} → f {x}) = g, which is ugly, but amounts to the
equality f = g.
("Implicit arguments are inserted eagerly in left-hand sides" https://agda.readthedocs.io/en/latest/language/implicit-arguments.html)
Our solution is to instead write f =[ Πᵢ A ] g. We
use a similar trick for _∼ᵢ_.
\begin{code}
-∼ᵢ : {X : 𝓤 ̇ } (A : X → 𝓥 ̇ ) → Πᵢ A → Πᵢ A → 𝓤 ⊔ 𝓥 ̇
-∼ᵢ A f g = ∀ x → f {x} = g {x}
syntax -∼ᵢ A f g = f ∼ᵢ[ A ] g
implicit-DN-funext : ∀ 𝓤 𝓥 → (𝓤 ⊔ 𝓥)⁺ ̇
implicit-DN-funext 𝓤 𝓥 = {X : 𝓤 ̇ } {A : X → 𝓥 ̇ } {f g : Πᵢ A}
→ f ∼ᵢ[ A ] g
→ f =[ Πᵢ A ] g
implicit-dfunext : funext 𝓤 𝓥 → implicit-DN-funext 𝓤 𝓥
implicit-dfunext fe {X} {A} {f} {g} h = ap implicit (dfunext fe (∼ᵢ-gives-∼ f g h))
\end{code}