From 5efde68f7cfcc93e279232a60aa8783686680524 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Anders=20=C3=85gren=20Thun=C3=A9?= Date: Mon, 20 Apr 2026 23:03:38 +0200 Subject: [PATCH] Define Disc using inductive identity --- src/Cat/Instances/Discrete.lagda.md | 162 ++++++++++------------------ 1 file changed, 58 insertions(+), 104 deletions(-) diff --git a/src/Cat/Instances/Discrete.lagda.md b/src/Cat/Instances/Discrete.lagda.md index 7b730ca5c..bb22a507c 100644 --- a/src/Cat/Instances/Discrete.lagda.md +++ b/src/Cat/Instances/Discrete.lagda.md @@ -8,6 +8,7 @@ open import Cat.Groupoid open import Cat.Morphism open import Cat.Prelude +open import Data.Id.Properties open import Data.Id.Base open import Data.Dec @@ -37,20 +38,22 @@ open _=>_ Given a [[groupoid]] $A$, we can see $A$ as a [[category]] with space of objects $A$ and path types $x \equiv y$ as $\hom$-sets $x \to y$. When $A$ is a [[set]], we call this the **discrete category** on $A$. +For technical reasons, we prefer to define this category using the +[[inductive identity]] type instead of the path type. ```agda Disc : (A : Type ℓ) → is-groupoid A → Precategory ℓ ℓ -Disc A A-grpd .Ob = A -Disc A A-grpd .Hom = _≡_ -Disc A A-grpd .Hom-set = A-grpd -Disc A A-grpd .id = refl -Disc A A-grpd ._∘_ p q = q ∙ p -Disc A A-grpd .idr _ = ∙-idl _ -Disc A A-grpd .idl _ = ∙-idr _ -Disc A A-grpd .assoc _ _ _ = sym (∙-assoc _ _ _) +Disc A A-grpd .Ob = A +Disc A A-grpd .Hom = _≡ᵢ_ +Disc A A-grpd .Hom-set = ≡ᵢ-is-hlevel' {n = 2} A-grpd +Disc A A-grpd .id = reflᵢ +Disc A A-grpd ._∘_ p q = q ∙ᵢ p +Disc A A-grpd .idr _ = refl +Disc A A-grpd .idl _ = ∙ᵢ-idr _ +Disc A A-grpd .assoc p q r = sym (∙ᵢ-assoc r q p) Disc' : Set ℓ → Precategory ℓ ℓ -Disc' A = Disc ∣ A ∣ h where abstract +Disc' A = Disc ∣ A ∣ h module Disc' where abstract h : is-groupoid ∣ A ∣ h = is-hlevel-suc 2 (A .is-tr) ``` @@ -60,26 +63,12 @@ By construction, this is a [[univalent|univalent category]] ```agda Disc-is-category : ∀ {A : Type ℓ} {A-grpd} → is-category (Disc A A-grpd) -Disc-is-category .to-path is = is .to -Disc-is-category .to-path-over is = ≅-pathp _ _ _ λ i j → is .to (i ∧ j) +Disc-is-category .to-path is = Id≃path.to (is .to) +Disc-is-category .to-path-over {a = a} is = ≅-pathp _ _ _ $ + Jᵢ (λ _ p → PathP (λ i → a ≡ᵢ Id≃path.to p i) reflᵢ p) refl (is .to) Disc-is-groupoid : ∀ {A : Type ℓ} {A-grpd} → is-pregroupoid (Disc A A-grpd) -Disc-is-groupoid p = make-invertible _ (sym p) (∙-invl p) (∙-invr p) -``` - -We can lift any function between the underlying types to a functor -between discrete categories. This is because every function -automatically respects equality in a functorial way. - -```agda -lift-disc - : ∀ {A : Set ℓ} {B : Set ℓ'} - → (∣ A ∣ → ∣ B ∣) - → Functor (Disc' A) (Disc' B) -lift-disc f .F₀ = f -lift-disc f .F₁ = ap f -lift-disc f .F-id = refl -lift-disc f .F-∘ p q = ap-∙ f q p +Disc-is-groupoid p = make-invertible _ (symᵢ p) (∙ᵢ-invl p) (∙ᵢ-invr p) ``` -Proving that our our $F_1$ is functorial involves a bunch of tedious -computations with equalities and a whole waterfall of absurd cases: +As a corollary, we can lift any function between underlying types to a +functor between discrete categories. ```agda - F .F-id {x} = refl - F .F-∘ {x} {y} {z} f g = - J (λ y g → ∀ {z} (f : y ≡ z) → go (g ∙ f) (x ≡ᵢ? z) ≡ go f (y ≡ᵢ? z) C.∘ go g (x ≡ᵢ? y)) - (λ f → J (λ z f → go (refl ∙ f) (x ≡ᵢ? z) ≡ go f (x ≡ᵢ? z) C.∘ C.id) (sym (C.idr _)) f) - g f +lift-disc : {A : Set ℓ} {B : Set ℓ'} → (∣ A ∣ → ∣ B ∣) → Functor (Disc' A) (Disc' B) +lift-disc {A = A} f = Disc-diagram (Disc'.h A) f ``` +Disc-into X F F₁ .F₀ = F +Disc-into X F F₁ .F₁ = F₁ +Disc-into X F F₁ .F-id = ≡ᵢ-is-hlevel' {n = 1} (X .is-tr) _ _ _ _ +Disc-into X F F₁ .F-∘ _ _ = ≡ᵢ-is-hlevel' {n = 1} (X .is-tr) _ _ _ _ -