open import 1Lab.Reflection.Signature
open import 1Lab.Path.IdentitySystem
open import 1Lab.Function.Embedding
open import 1Lab.Reflection.HLevel
open import 1Lab.Reflection.Subst
open import 1Lab.HIT.Truncation
open import 1Lab.HLevel.Closure
open import 1Lab.Reflection
open import 1Lab.Type.Sigma
open import 1Lab.Resizing
open import 1Lab.Type.Pi
open import 1Lab.HLevel
open import 1Lab.Equiv
open import 1Lab.Path
open import 1Lab.Type
open import Data.Nat.Base
module 1Lab.Extensionality where
private variable
ℓ ℓ' ℓ'' ℓr : Level
A B C : Type ℓ
P Q R : A → Type ℓ
record Extensional (A : Type ℓ) ℓ-rel : Type (ℓ ⊔ lsuc ℓ-rel) where
no-eta-equality
field
Pathᵉ : A → A → Type ℓ-rel
reflᵉ : ∀ x → Pathᵉ x x
idsᵉ : is-identity-system Pathᵉ reflᵉ
open Extensional using (Pathᵉ ; reflᵉ ; idsᵉ) public
instance
Extensional-default : Extensional A (level-of A)
Extensional-default .Pathᵉ = _≡_
Extensional-default .reflᵉ _ = refl
Extensional-default .idsᵉ = Path-identity-system
{-# INCOHERENT Extensional-default #-}
Extensional-Lift : ⦃ Extensional A ℓr ⦄ → Extensional (Lift ℓ' A) ℓr
Extensional-Lift ⦃ sa ⦄ .Pathᵉ (lift x) (lift y) = sa .Pathᵉ x y
Extensional-Lift ⦃ sa ⦄ .reflᵉ (lift x) = sa .reflᵉ x
Extensional-Lift ⦃ sa ⦄ .idsᵉ .to-path p = ap lift (sa .idsᵉ .to-path p)
Extensional-Lift ⦃ sa ⦄ .idsᵉ .to-path-over p = sa .idsᵉ .to-path-over p
Extensional-Π
: ⦃ ∀ {x} → Extensional (P x) ℓr ⦄
→ Extensional ((x : A) → P x) (level-of A ⊔ ℓr)
Extensional-Π ⦃ sb ⦄ .Pathᵉ f g = ∀ x → Pathᵉ sb (f x) (g x)
Extensional-Π ⦃ sb ⦄ .reflᵉ f x = reflᵉ sb (f x)
Extensional-Π ⦃ sb ⦄ .idsᵉ .to-path h = funext λ i → sb .idsᵉ .to-path (h i)
Extensional-Π ⦃ sb ⦄ .idsᵉ .to-path-over h = funextP λ i → sb .idsᵉ .to-path-over (h i)
{-# OVERLAPPABLE Extensional-Π #-}
Extensional-Π'
: ⦃ ∀ {x} → Extensional (P x) ℓr ⦄
→ Extensional ({x : A} → P x) (level-of A ⊔ ℓr)
Extensional-Π' ⦃ sb ⦄ .Pathᵉ f g = ∀ {x} → Pathᵉ (sb {x}) f g
Extensional-Π' ⦃ sb ⦄ .reflᵉ f = reflᵉ sb f
Extensional-Π' ⦃ sb ⦄ .idsᵉ .to-path h i = sb .idsᵉ .to-path h i
Extensional-Π' ⦃ sb ⦄ .idsᵉ .to-path-over h i = sb .idsᵉ .to-path-over h i
Extensional-Π''
: ⦃ ∀ ⦃ x ⦄ → Extensional (P x) ℓr ⦄
→ Extensional (⦃ x : A ⦄ → P x) (level-of A ⊔ ℓr)
Extensional-Π'' ⦃ sb ⦄ .Pathᵉ f g = ∀ ⦃ x ⦄ → Pathᵉ (sb ⦃ x ⦄) f g
Extensional-Π'' ⦃ sb ⦄ .reflᵉ f = reflᵉ sb f
Extensional-Π'' ⦃ sb ⦄ .idsᵉ .to-path h i = sb .idsᵉ .to-path h i
Extensional-Π'' ⦃ sb ⦄ .idsᵉ .to-path-over h i = sb .idsᵉ .to-path-over h i
Extensional-×
: ∀ {ℓ ℓ' ℓr ℓs} {A : Type ℓ} {B : Type ℓ'}
→ ⦃ sa : Extensional A ℓr ⦄
→ ⦃ sb : Extensional B ℓs ⦄
→ Extensional (A × B) (ℓr ⊔ ℓs)
Extensional-× ⦃ sa ⦄ ⦃ sb ⦄ .Pathᵉ (x , y) (x' , y') = Pathᵉ sa x x' × Pathᵉ sb y y'
Extensional-× ⦃ sa ⦄ ⦃ sb ⦄ .reflᵉ (x , y) = reflᵉ sa x , reflᵉ sb y
Extensional-× ⦃ sa ⦄ ⦃ sb ⦄ .idsᵉ .to-path (p , q) = ap₂ _,_
(sa .idsᵉ .to-path p)
(sb .idsᵉ .to-path q)
Extensional-× ⦃ sa ⦄ ⦃ sb ⦄ .idsᵉ .to-path-over (p , q) = Σ-pathp
(sa .idsᵉ .to-path-over p)
(sb .idsᵉ .to-path-over q)
Extensional-uncurry
: ∀ {ℓ ℓ' ℓ'' ℓr} {A : Type ℓ} {B : A → Type ℓ'} {C : (x : A) → B x → Type ℓ''}
→ ⦃ sb : Extensional ((x : A) (y : B x) → C x y) ℓr ⦄
→ Extensional ((p : Σ A B) → C (p .fst) (p .snd)) ℓr
Extensional-uncurry ⦃ sb ⦄ .Pathᵉ f g = sb .Pathᵉ (curry f) (curry g)
Extensional-uncurry ⦃ sb ⦄ .reflᵉ f = sb .reflᵉ (curry f)
Extensional-uncurry ⦃ sb = sb ⦄ .idsᵉ .to-path h i (a , b) = sb .idsᵉ .to-path h i a b
Extensional-uncurry ⦃ sb = sb ⦄ .idsᵉ .to-path-over h = sb .idsᵉ .to-path-over h
Extensional-lift-map
: ∀ {ℓ ℓ' ℓ'' ℓr} {A : Type ℓ} {B : Lift ℓ' A → Type ℓ''}
→ ⦃ sa : Extensional ((x : A) → B (lift x)) ℓr ⦄
→ Extensional ((x : Lift ℓ' A) → B x) ℓr
Extensional-lift-map ⦃ sa = sa ⦄ .Pathᵉ f g = sa .Pathᵉ (f ∘ lift) (g ∘ lift)
Extensional-lift-map ⦃ sa = sa ⦄ .reflᵉ x = sa .reflᵉ (x ∘ lift)
Extensional-lift-map ⦃ sa = sa ⦄ .idsᵉ .to-path h i (lift x) = sa .idsᵉ .to-path h i x
Extensional-lift-map ⦃ sa = sa ⦄ .idsᵉ .to-path-over h = sa .idsᵉ .to-path-over h
ext
: ∀ {ℓ ℓr} {A : Type ℓ} {x y : A} ⦃ r : Extensional A ℓr ⦄
→ Pathᵉ r x y → x ≡ y
ext ⦃ r ⦄ p = r .idsᵉ .to-path p
private
trivial-worker
: ∀ {ℓ ℓr} {A : Type ℓ} (r : Extensional A ℓr)
→ (x y : A) → Term → TC ⊤
trivial-worker r x y goal = try where
error : ∀ {ℓ} {A : Type ℓ} → TC A
try : TC ⊤
try = do
`r ← wait-for-type =<< quoteTC r
`x ← quoteTC x
unify goal (it reflᵉ ##ₙ `r ##ₙ `x) <|> error
error = do
`x ← quoteTC x
`y ← quoteTC y
typeError
[ "trivial! failed: the values\n "
, termErr `x
, "\nand\n "
, termErr `y
, "\nare not extensionally equal by refl.\n"
]
opaque
trivial!
: ∀ {ℓ ℓr} {A : Type ℓ} {x y : A}
→ ⦃ r : Extensional A ℓr ⦄
→ {@(tactic trivial-worker r x y) p : Pathᵉ r x y}
→ x ≡ y
trivial! ⦃ r ⦄ {p = p} = r .idsᵉ .to-path p
trivial-iso!
: ∀ {ℓ ℓ' ℓr ℓs} {A : Type ℓ} {B : Type ℓ'}
→ ⦃ r : Extensional (A → A) ℓr ⦄
→ ⦃ s : Extensional (B → B) ℓs ⦄
→ (f : A → B)
→ (g : B → A)
→ {@(tactic trivial-worker r (g ∘ f) id) p : Pathᵉ r (g ∘ f) id}
→ {@(tactic trivial-worker s (f ∘ g) id) q : Pathᵉ s (f ∘ g) id}
→ Iso A B
trivial-iso! ⦃ r ⦄ ⦃ s ⦄ f g {p = p} {q = q} =
f , iso g (happly (s .idsᵉ .to-path q)) (happly (r .idsᵉ .to-path p))
abstract
unext : ∀ {ℓ ℓr} {A : Type ℓ} ⦃ e : Extensional A ℓr ⦄ {x y : A} → x ≡ y → e .Pathᵉ x y
unext ⦃ e ⦄ {x = x} p = transport (λ i → e .Pathᵉ x (p i)) (e .reflᵉ x)
macro
reext!
: ∀ {ℓ ℓr} {A : Type ℓ} ⦃ ea : Extensional A ℓr ⦄ {x y : A}
→ x ≡ y → Term → TC ⊤
reext! p goal = do
`p ← quoteTC p
unify goal (def (quote ext) [ argN (def (quote unext) [ argN `p ]) ])
Pathᵉ-is-hlevel
: ∀ {ℓ ℓr} {A : Type ℓ} n (sa : Extensional A ℓr)
→ is-hlevel A (suc n)
→ ∀ {x y}
→ is-hlevel (Pathᵉ sa x y) n
Pathᵉ-is-hlevel n sa hl =
Equiv→is-hlevel _ (identity-system-gives-path (sa .idsᵉ)) (Path-is-hlevel' _ hl _ _)
embedding→extensional
: ∀ {ℓ ℓ' ℓr} {A : Type ℓ} {B : Type ℓ'}
→ (f : A ↪ B)
→ Extensional B ℓr
→ Extensional A ℓr
embedding→extensional f ext .Pathᵉ x y = Pathᵉ ext (f .fst x) (f .fst y)
embedding→extensional f ext .reflᵉ x = reflᵉ ext (f .fst x)
embedding→extensional f ext .idsᵉ =
pullback-identity-system (ext .idsᵉ) f
iso→extensional
: ∀ {ℓ ℓ' ℓr} {A : Type ℓ} {B : Type ℓ'}
→ Iso A B
→ Extensional B ℓr
→ Extensional A ℓr
iso→extensional f ext =
embedding→extensional (Iso→Embedding f) ext
injection→extensional
: ∀ {ℓ ℓ' ℓr} {A : Type ℓ} {B : Type ℓ'}
→ is-set B
→ {f : A → B}
→ (∀ {x y} → f x ≡ f y → x ≡ y)
→ Extensional B ℓr
→ Extensional A ℓr
injection→extensional b-set {f} inj ext .Pathᵉ x y = ext .Pathᵉ (f x) (f y)
injection→extensional b-set {f} inj ext .reflᵉ x = ext .reflᵉ (f x)
injection→extensional b-set {f} inj ext .idsᵉ .to-path x = inj (ext .idsᵉ .to-path x)
injection→extensional b-set {f} inj ext .idsᵉ .to-path-over p =
is-prop→pathp (λ i → Pathᵉ-is-hlevel 1 ext b-set) _ _
injection→extensional!
: ∀ {ℓ ℓ' ℓr} {A : Type ℓ} {B : Type ℓ'}
→ ⦃ _ : H-Level B 2 ⦄
→ {f : A → B}
→ (∀ {x y} → f x ≡ f y → x ≡ y)
→ Extensional B ℓr
→ Extensional A ℓr
injection→extensional! = injection→extensional (hlevel 2)
Σ-prop-extensional
: ∀ {ℓ ℓ' ℓr} {A : Type ℓ} {B : A → Type ℓ'}
→ (∀ x → is-prop (B x))
→ Extensional A ℓr
→ Extensional (Σ A B) ℓr
Σ-prop-extensional bprop = embedding→extensional (fst , Subset-proj-embedding bprop)
instance
Extensional-Σ-trunc
: ∀ {ℓ ℓ' ℓr} {A : Type ℓ} {B : A → Type ℓ'}
→ ⦃ ea : Extensional A ℓr ⦄ → Extensional (Σ A λ x → ∥ B x ∥) ℓr
Extensional-Σ-trunc ⦃ ea ⦄ = Σ-prop-extensional (λ x → hlevel 1) ea
Extensional-Σ-□
: ∀ {ℓ ℓ' ℓr} {A : Type ℓ} {B : A → Type ℓ'}
→ ⦃ ea : Extensional A ℓr ⦄ → Extensional (Σ A λ x → □ (B x)) ℓr
Extensional-Σ-□ ⦃ ea ⦄ = Σ-prop-extensional (λ x → hlevel 1) ea
Extensional-equiv
: ∀ {ℓ ℓ' ℓr} {A : Type ℓ} {B : Type ℓ'}
→ ⦃ ea : Extensional (A → B) ℓr ⦄ → Extensional (A ≃ B) ℓr
Extensional-equiv ⦃ ea ⦄ = Σ-prop-extensional (λ x → is-equiv-is-prop _) ea
Extensional-tr-map
: ∀ {ℓ ℓ' ℓr} {A : Type ℓ} {B : Type ℓ'}
→ ⦃ bset : H-Level B 2 ⦄
→ ⦃ ea : Extensional (A → B) ℓr ⦄
→ Extensional (∥ A ∥ → B) ℓr
Extensional-tr-map ⦃ ea = ea ⦄ =
injection→extensional! {f = λ f → f ∘ inc}
(λ p → funext $ ∥-∥-elim (λ _ → hlevel 1) (happly p)) ea
private module test where
_ : {f g : A → B} → ((x : A) → f x ≡ g x) → f ≡ g
_ = ext
_ : {f g : A × B → C} → ((a : A) (b : B) → f (a , b) ≡ g (a , b)) → f ≡ g
_ = ext
_ : {f g : Σ A P → B} → ((a : A) (b : P a) → f (a , b) ≡ g (a , b)) → f ≡ g
_ = ext
open Lift
_ : {f g : Σ (Lift ℓ' A) (λ x → Lift ℓ' (P (x .lower))) → Lift ℓ'' B}
→ ((a : A) (b : P a) → f (lift a , lift b) .lower ≡ g (lift a , lift b) .lower)
→ f ≡ g
_ = ext
_ : {f g : A → B ≃ C} → ((a : A) (b : B) → f a .fst b ≡ g a .fst b) → f ≡ g
_ = ext