-- | Univalent categories -- -- This module defines: -- -- Categories -- ========== -- -- Types -- ------ -- -- Object, Arrow -- -- Data -- ---- -- πŸ™; the identity arrow -- _∘_; function composition -- -- Laws -- ---- -- -- associativity, identity, arrows form sets, univalence. -- -- Lemmas -- ------ -- -- Propositionality for all laws about the category. {-# OPTIONS --allow-unsolved-metas --cubical #-} module Cat.Category where open import Cat.Prelude renaming ( proj₁ to fst ; projβ‚‚ to snd ) import Function ------------------ -- * Categories -- ------------------ -- | Raw categories -- -- This record desribes the data that a category consist of as well as some laws -- about these. The laws defined are the types the propositions - not the -- witnesses to them! record RawCategory (β„“a β„“b : Level) : Set (lsuc (β„“a βŠ” β„“b)) where no-eta-equality field Object : Set β„“a Arrow : Object β†’ Object β†’ Set β„“b πŸ™ : {A : Object} β†’ Arrow A A _∘_ : {A B C : Object} β†’ Arrow B C β†’ Arrow A B β†’ Arrow A C infixl 10 _∘_ _>>>_ -- | Operations on data domain : {a b : Object} β†’ Arrow a b β†’ Object domain {a} _ = a codomain : {a b : Object} β†’ Arrow a b β†’ Object codomain {b = b} _ = b _>>>_ : {A B C : Object} β†’ (Arrow A B) β†’ (Arrow B C) β†’ Arrow A C f >>> g = g ∘ f -- | Laws about the data -- FIXME It seems counter-intuitive that the normal-form is on the -- right-hand-side. IsAssociative : Set (β„“a βŠ” β„“b) IsAssociative = βˆ€ {A B C D} {f : Arrow A B} {g : Arrow B C} {h : Arrow C D} β†’ h ∘ (g ∘ f) ≑ (h ∘ g) ∘ f IsIdentity : ({A : Object} β†’ Arrow A A) β†’ Set (β„“a βŠ” β„“b) IsIdentity id = {A B : Object} {f : Arrow A B} β†’ id ∘ f ≑ f Γ— f ∘ id ≑ f ArrowsAreSets : Set (β„“a βŠ” β„“b) ArrowsAreSets = βˆ€ {A B : Object} β†’ isSet (Arrow A B) IsInverseOf : βˆ€ {A B} β†’ (Arrow A B) β†’ (Arrow B A) β†’ Set β„“b IsInverseOf = Ξ» f g β†’ g ∘ f ≑ πŸ™ Γ— f ∘ g ≑ πŸ™ Isomorphism : βˆ€ {A B} β†’ (f : Arrow A B) β†’ Set β„“b Isomorphism {A} {B} f = Ξ£[ g ∈ Arrow B A ] IsInverseOf f g _β‰…_ : (A B : Object) β†’ Set β„“b _β‰…_ A B = Ξ£[ f ∈ Arrow A B ] (Isomorphism f) module _ {A B : Object} where Epimorphism : {X : Object } β†’ (f : Arrow A B) β†’ Set β„“b Epimorphism {X} f = (gβ‚€ g₁ : Arrow B X) β†’ gβ‚€ ∘ f ≑ g₁ ∘ f β†’ gβ‚€ ≑ g₁ Monomorphism : {X : Object} β†’ (f : Arrow A B) β†’ Set β„“b Monomorphism {X} f = (gβ‚€ g₁ : Arrow X A) β†’ f ∘ gβ‚€ ≑ f ∘ g₁ β†’ gβ‚€ ≑ g₁ IsInitial : Object β†’ Set (β„“a βŠ” β„“b) IsInitial I = {X : Object} β†’ isContr (Arrow I X) IsTerminal : Object β†’ Set (β„“a βŠ” β„“b) IsTerminal T = {X : Object} β†’ isContr (Arrow X T) Initial : Set (β„“a βŠ” β„“b) Initial = Ξ£ Object IsInitial Terminal : Set (β„“a βŠ” β„“b) Terminal = Ξ£ Object IsTerminal -- | Univalence is indexed by a raw category as well as an identity proof. module Univalence (isIdentity : IsIdentity πŸ™) where -- | The identity isomorphism idIso : (A : Object) β†’ A β‰… A idIso A = πŸ™ , πŸ™ , isIdentity -- | Extract an isomorphism from an equality -- -- [HoTT Β§9.1.4] id-to-iso : (A B : Object) β†’ A ≑ B β†’ A β‰… B id-to-iso A B eq = transp (\ i β†’ A β‰… eq i) (idIso A) Univalent : Set (β„“a βŠ” β„“b) Univalent = {A B : Object} β†’ isEquiv (A ≑ B) (A β‰… B) (id-to-iso A B) -- A perhaps more readable version of univalence: Univalent≃ = {A B : Object} β†’ (A ≑ B) ≃ (A β‰… B) -- | Equivalent formulation of univalence. Univalent[Contr] : Set _ Univalent[Contr] = βˆ€ A β†’ isContr (Ξ£[ X ∈ Object ] A β‰… X) -- From: Thierry Coquand -- Date: Wed, Mar 21, 2018 at 3:12 PM -- -- This is not so straight-forward so you can assume it postulate from[Contr] : Univalent[Contr] β†’ Univalent -- | The mere proposition of being a category. -- -- Also defines a few lemmas: -- -- iso-is-epi : Isomorphism f β†’ Epimorphism {X = X} f -- iso-is-mono : Isomorphism f β†’ Monomorphism {X = X} f -- -- Sans `univalent` this would be what is referred to as a pre-category in -- [HoTT]. record IsCategory {β„“a β„“b : Level} (β„‚ : RawCategory β„“a β„“b) : Set (lsuc (β„“a βŠ” β„“b)) where open RawCategory β„‚ public field isAssociative : IsAssociative isIdentity : IsIdentity πŸ™ arrowsAreSets : ArrowsAreSets open Univalence isIdentity public field univalent : Univalent leftIdentity : {A B : Object} {f : Arrow A B} β†’ πŸ™ ∘ f ≑ f leftIdentity {A} {B} {f} = fst (isIdentity {A = A} {B} {f}) rightIdentity : {A B : Object} {f : Arrow A B} β†’ f ∘ πŸ™ ≑ f rightIdentity {A} {B} {f} = snd (isIdentity {A = A} {B} {f}) ------------ -- Lemmas -- ------------ -- | Relation between iso- epi- and mono- morphisms. module _ {A B : Object} {X : Object} (f : Arrow A B) where isoβ†’epi : Isomorphism f β†’ Epimorphism {X = X} f isoβ†’epi (f- , left-inv , right-inv) gβ‚€ g₁ eq = begin gβ‚€ β‰‘βŸ¨ sym rightIdentity ⟩ gβ‚€ ∘ πŸ™ β‰‘βŸ¨ cong (_∘_ gβ‚€) (sym right-inv) ⟩ gβ‚€ ∘ (f ∘ f-) β‰‘βŸ¨ isAssociative ⟩ (gβ‚€ ∘ f) ∘ f- β‰‘βŸ¨ cong (Ξ» Ο† β†’ Ο† ∘ f-) eq ⟩ (g₁ ∘ f) ∘ f- β‰‘βŸ¨ sym isAssociative ⟩ g₁ ∘ (f ∘ f-) β‰‘βŸ¨ cong (_∘_ g₁) right-inv ⟩ g₁ ∘ πŸ™ β‰‘βŸ¨ rightIdentity ⟩ g₁ ∎ isoβ†’mono : Isomorphism f β†’ Monomorphism {X = X} f isoβ†’mono (f- , left-inv , right-inv) gβ‚€ g₁ eq = begin gβ‚€ β‰‘βŸ¨ sym leftIdentity ⟩ πŸ™ ∘ gβ‚€ β‰‘βŸ¨ cong (Ξ» Ο† β†’ Ο† ∘ gβ‚€) (sym left-inv) ⟩ (f- ∘ f) ∘ gβ‚€ β‰‘βŸ¨ sym isAssociative ⟩ f- ∘ (f ∘ gβ‚€) β‰‘βŸ¨ cong (_∘_ f-) eq ⟩ f- ∘ (f ∘ g₁) β‰‘βŸ¨ isAssociative ⟩ (f- ∘ f) ∘ g₁ β‰‘βŸ¨ cong (Ξ» Ο† β†’ Ο† ∘ g₁) left-inv ⟩ πŸ™ ∘ g₁ β‰‘βŸ¨ leftIdentity ⟩ g₁ ∎ isoβ†’epiΓ—mono : Isomorphism f β†’ Epimorphism {X = X} f Γ— Monomorphism {X = X} f isoβ†’epiΓ—mono iso = isoβ†’epi iso , isoβ†’mono iso -- | The formulation of univalence expressed with _≃_ is trivially admissable - -- just "forget" the equivalence. univalent≃ : Univalent≃ univalent≃ = _ , univalent -- | All projections are propositions. module Propositionality where propIsAssociative : isProp IsAssociative propIsAssociative x y i = arrowsAreSets _ _ x y i propIsIdentity : βˆ€ {f : βˆ€ {A} β†’ Arrow A A} β†’ isProp (IsIdentity f) propIsIdentity a b i = arrowsAreSets _ _ (fst a) (fst b) i , arrowsAreSets _ _ (snd a) (snd b) i propArrowIsSet : isProp (βˆ€ {A B} β†’ isSet (Arrow A B)) propArrowIsSet a b i = isSetIsProp a b i propIsInverseOf : βˆ€ {A B f g} β†’ isProp (IsInverseOf {A} {B} f g) propIsInverseOf x y = Ξ» i β†’ let h : fst x ≑ fst y h = arrowsAreSets _ _ (fst x) (fst y) hh : snd x ≑ snd y hh = arrowsAreSets _ _ (snd x) (snd y) in h i , hh i module _ {A B : Object} {f : Arrow A B} where isoIsProp : isProp (Isomorphism f) isoIsProp a@(g , Ξ· , Ξ΅) a'@(g' , Ξ·' , Ξ΅') = lemSig (Ξ» g β†’ propIsInverseOf) a a' geq where geq : g ≑ g' geq = begin g β‰‘βŸ¨ sym rightIdentity ⟩ g ∘ πŸ™ β‰‘βŸ¨ cong (Ξ» Ο† β†’ g ∘ Ο†) (sym Ξ΅') ⟩ g ∘ (f ∘ g') β‰‘βŸ¨ isAssociative ⟩ (g ∘ f) ∘ g' β‰‘βŸ¨ cong (Ξ» Ο† β†’ Ο† ∘ g') Ξ· ⟩ πŸ™ ∘ g' β‰‘βŸ¨ leftIdentity ⟩ g' ∎ propUnivalent : isProp Univalent propUnivalent a b i = propPi (Ξ» iso β†’ propIsContr) a b i propIsTerminal : βˆ€ T β†’ isProp (IsTerminal T) propIsTerminal T x y i {X} = res X i where module _ (X : Object) where open Ξ£ (x {X}) renaming (proj₁ to fx ; projβ‚‚ to cx) open Ξ£ (y {X}) renaming (proj₁ to fy ; projβ‚‚ to cy) fp : fx ≑ fy fp = cx fy prop : (x : Arrow X T) β†’ isProp (βˆ€ f β†’ x ≑ f) prop x = propPi (Ξ» y β†’ arrowsAreSets x y) cp : (Ξ» i β†’ βˆ€ f β†’ fp i ≑ f) [ cx ≑ cy ] cp = lemPropF prop fp res : (fx , cx) ≑ (fy , cy) res i = fp i , cp i -- | Terminal objects are propositional - a.k.a uniqueness of terminal -- | objects. -- -- Having two terminal objects induces an isomorphism between them - and -- because of univalence this is equivalent to equality. propTerminal : isProp Terminal propTerminal Xt Yt = res where open Ξ£ Xt renaming (proj₁ to X ; projβ‚‚ to Xit) open Ξ£ Yt renaming (proj₁ to Y ; projβ‚‚ to Yit) open Ξ£ (Xit {Y}) renaming (proj₁ to Yβ†’X) using () open Ξ£ (Yit {X}) renaming (proj₁ to Xβ†’Y) using () open import Cat.Equivalence hiding (_β‰…_) -- Need to show `left` and `right`, what we know is that the arrows are -- unique. Well, I know that if I compose these two arrows they must give -- the identity, since also the identity is the unique such arrow (by X -- and Y both being terminal objects.) Xprop : isProp (Arrow X X) Xprop f g = trans (sym (snd Xit f)) (snd Xit g) Yprop : isProp (Arrow Y Y) Yprop f g = trans (sym (snd Yit f)) (snd Yit g) left : Yβ†’X ∘ Xβ†’Y ≑ πŸ™ left = Xprop _ _ right : Xβ†’Y ∘ Yβ†’X ≑ πŸ™ right = Yprop _ _ iso : X β‰… Y iso = Xβ†’Y , Yβ†’X , left , right fromIso : X β‰… Y β†’ X ≑ Y fromIso = fst (Equiv≃.toIso (X ≑ Y) (X β‰… Y) univalent) p0 : X ≑ Y p0 = fromIso iso p1 : (Ξ» i β†’ IsTerminal (p0 i)) [ Xit ≑ Yit ] p1 = lemPropF propIsTerminal p0 res : Xt ≑ Yt res i = p0 i , p1 i -- Merely the dual of the above statement. propIsInitial : βˆ€ I β†’ isProp (IsInitial I) propIsInitial I x y i {X} = res X i where module _ (X : Object) where open Ξ£ (x {X}) renaming (proj₁ to fx ; projβ‚‚ to cx) open Ξ£ (y {X}) renaming (proj₁ to fy ; projβ‚‚ to cy) fp : fx ≑ fy fp = cx fy prop : (x : Arrow I X) β†’ isProp (βˆ€ f β†’ x ≑ f) prop x = propPi (Ξ» y β†’ arrowsAreSets x y) cp : (Ξ» i β†’ βˆ€ f β†’ fp i ≑ f) [ cx ≑ cy ] cp = lemPropF prop fp res : (fx , cx) ≑ (fy , cy) res i = fp i , cp i propInitial : isProp Initial propInitial Xi Yi = {!!} where open Ξ£ Xi renaming (proj₁ to X ; projβ‚‚ to Xii) open Ξ£ Yi renaming (proj₁ to Y ; projβ‚‚ to Yii) open Ξ£ (Xii {Y}) renaming (proj₁ to Yβ†’X) using () open Ξ£ (Yii {X}) renaming (proj₁ to Xβ†’Y) using () open import Cat.Equivalence hiding (_β‰…_) -- Need to show `left` and `right`, what we know is that the arrows are -- unique. Well, I know that if I compose these two arrows they must give -- the identity, since also the identity is the unique such arrow (by X -- and Y both being terminal objects.) Xprop : isProp (Arrow X X) Xprop f g = trans (sym (snd Xii f)) (snd Xii g) Yprop : isProp (Arrow Y Y) Yprop f g = trans (sym (snd Yii f)) (snd Yii g) left : Yβ†’X ∘ Xβ†’Y ≑ πŸ™ left = Yprop _ _ right : Xβ†’Y ∘ Yβ†’X ≑ πŸ™ right = Xprop _ _ iso : X β‰… Y iso = Yβ†’X , Xβ†’Y , right , left fromIso : X β‰… Y β†’ X ≑ Y fromIso = fst (Equiv≃.toIso (X ≑ Y) (X β‰… Y) univalent) p0 : X ≑ Y p0 = fromIso iso p1 : (Ξ» i β†’ IsInitial (p0 i)) [ Xii ≑ Yii ] p1 = lemPropF propIsInitial p0 res : Xi ≑ Yi res i = p0 i , p1 i -- | Propositionality of being a category module _ {β„“a β„“b : Level} (β„‚ : RawCategory β„“a β„“b) where open RawCategory β„‚ open Univalence private module _ (x y : IsCategory β„‚) where module X = IsCategory x module Y = IsCategory y -- In a few places I use the result of propositionality of the various -- projections of `IsCategory` - Here I arbitrarily chose to use this -- result from `x : IsCategory C`. I don't know which (if any) possibly -- adverse effects this may have. module Prop = X.Propositionality isIdentity : (Ξ» _ β†’ IsIdentity πŸ™) [ X.isIdentity ≑ Y.isIdentity ] isIdentity = Prop.propIsIdentity X.isIdentity Y.isIdentity U : βˆ€ {a : IsIdentity πŸ™} β†’ (Ξ» _ β†’ IsIdentity πŸ™) [ X.isIdentity ≑ a ] β†’ (b : Univalent a) β†’ Set _ U eqwal univ = (Ξ» i β†’ Univalent (eqwal i)) [ X.univalent ≑ univ ] P : (y : IsIdentity πŸ™) β†’ (Ξ» _ β†’ IsIdentity πŸ™) [ X.isIdentity ≑ y ] β†’ Set _ P y eq = βˆ€ (univ : Univalent y) β†’ U eq univ p : βˆ€ (b' : Univalent X.isIdentity) β†’ (Ξ» _ β†’ Univalent X.isIdentity) [ X.univalent ≑ b' ] p univ = Prop.propUnivalent X.univalent univ helper : P Y.isIdentity isIdentity helper = pathJ P p Y.isIdentity isIdentity eqUni : U isIdentity Y.univalent eqUni = helper Y.univalent done : x ≑ y IsCategory.isAssociative (done i) = Prop.propIsAssociative X.isAssociative Y.isAssociative i IsCategory.isIdentity (done i) = isIdentity i IsCategory.arrowsAreSets (done i) = Prop.propArrowIsSet X.arrowsAreSets Y.arrowsAreSets i IsCategory.univalent (done i) = eqUni i propIsCategory : isProp (IsCategory β„‚) propIsCategory = done -- | Univalent categories -- -- Just bundles up the data with witnesses inhabiting the propositions. record Category (β„“a β„“b : Level) : Set (lsuc (β„“a βŠ” β„“b)) where field raw : RawCategory β„“a β„“b {{isCategory}} : IsCategory raw open IsCategory isCategory public -- The fact that being a category is a mere proposition gives rise to this -- equality principle for categories. module _ {β„“a β„“b : Level} {β„‚ 𝔻 : Category β„“a β„“b} where private module β„‚ = Category β„‚ module 𝔻 = Category 𝔻 module _ (rawEq : β„‚.raw ≑ 𝔻.raw) where private isCategoryEq : (Ξ» i β†’ IsCategory (rawEq i)) [ β„‚.isCategory ≑ 𝔻.isCategory ] isCategoryEq = lemPropF propIsCategory rawEq Category≑ : β„‚ ≑ 𝔻 Category≑ i = record { raw = rawEq i ; isCategory = isCategoryEq i } -- | Syntax for arrows- and composition in a given category. module _ {β„“a β„“b : Level} (β„‚ : Category β„“a β„“b) where open Category β„‚ _[_,_] : (A : Object) β†’ (B : Object) β†’ Set β„“b _[_,_] = Arrow _[_∘_] : {A B C : Object} β†’ (g : Arrow B C) β†’ (f : Arrow A B) β†’ Arrow A C _[_∘_] = _∘_ -- | The opposite category -- -- The opposite category is the category where the direction of the arrows are -- flipped. module Opposite {β„“a β„“b : Level} where module _ (β„‚ : Category β„“a β„“b) where private module β„‚ = Category β„‚ opRaw : RawCategory β„“a β„“b RawCategory.Object opRaw = β„‚.Object RawCategory.Arrow opRaw = Function.flip β„‚.Arrow RawCategory.πŸ™ opRaw = β„‚.πŸ™ RawCategory._∘_ opRaw = Function.flip β„‚._∘_ open RawCategory opRaw isIdentity : IsIdentity πŸ™ isIdentity = swap β„‚.isIdentity open Univalence isIdentity module _ {A B : β„‚.Object} where open import Cat.Equivalence as Equivalence hiding (_β‰…_) k : Equivalence.Isomorphism (β„‚.id-to-iso A B) k = Equiv≃.toIso _ _ β„‚.univalent open Ξ£ k renaming (proj₁ to f ; projβ‚‚ to inv) open AreInverses inv _βŠ™_ = Function._∘_ infixr 9 _βŠ™_ -- f : A β„‚.β‰… B β†’ A ≑ B flipDem : A β‰… B β†’ A β„‚.β‰… B flipDem (f , g , inv) = g , f , inv flopDem : A β„‚.β‰… B β†’ A β‰… B flopDem (f , g , inv) = g , f , inv flipInv : βˆ€ {x} β†’ (flipDem βŠ™ flopDem) x ≑ x flipInv = refl -- Shouldn't be necessary to use `arrowsAreSets` here, but we have it, -- so why not? lem : (p : A ≑ B) β†’ id-to-iso A B p ≑ flopDem (β„‚.id-to-iso A B p) lem p i = l≑r i where l = id-to-iso A B p r = flopDem (β„‚.id-to-iso A B p) open Ξ£ l renaming (proj₁ to l-obv ; projβ‚‚ to l-areInv) open Ξ£ l-areInv renaming (proj₁ to l-invs ; projβ‚‚ to l-iso) open Ξ£ l-iso renaming (proj₁ to l-l ; projβ‚‚ to l-r) open Ξ£ r renaming (proj₁ to r-obv ; projβ‚‚ to r-areInv) open Ξ£ r-areInv renaming (proj₁ to r-invs ; projβ‚‚ to r-iso) open Ξ£ r-iso renaming (proj₁ to r-l ; projβ‚‚ to r-r) l-obv≑r-obv : l-obv ≑ r-obv l-obv≑r-obv = refl l-invs≑r-invs : l-invs ≑ r-invs l-invs≑r-invs = refl l-l≑r-l : l-l ≑ r-l l-l≑r-l = β„‚.arrowsAreSets _ _ l-l r-l l-r≑r-r : l-r ≑ r-r l-r≑r-r = β„‚.arrowsAreSets _ _ l-r r-r l≑r : l ≑ r l≑r i = l-obv≑r-obv i , l-invs≑r-invs i , l-l≑r-l i , l-r≑r-r i ff : A β‰… B β†’ A ≑ B ff = f βŠ™ flipDem -- inv : AreInverses (β„‚.id-to-iso A B) f invv : AreInverses (id-to-iso A B) ff -- recto-verso : β„‚.id-to-iso A B ∘ f ≑ idFun (A β„‚.β‰… B) invv = record { verso-recto = funExt (Ξ» x β†’ begin (ff βŠ™ id-to-iso A B) x β‰‘βŸ¨βŸ© (f βŠ™ flipDem βŠ™ id-to-iso A B) x β‰‘βŸ¨ cong (Ξ» Ο† β†’ Ο† x) (cong (Ξ» Ο† β†’ f βŠ™ flipDem βŠ™ Ο†) (funExt lem)) ⟩ (f βŠ™ flipDem βŠ™ flopDem βŠ™ β„‚.id-to-iso A B) x β‰‘βŸ¨βŸ© (f βŠ™ β„‚.id-to-iso A B) x β‰‘βŸ¨ (Ξ» i β†’ verso-recto i x) ⟩ x ∎) ; recto-verso = funExt (Ξ» x β†’ begin (id-to-iso A B βŠ™ f βŠ™ flipDem) x β‰‘βŸ¨ cong (Ξ» Ο† β†’ Ο† x) (cong (Ξ» Ο† β†’ Ο† βŠ™ f βŠ™ flipDem) (funExt lem)) ⟩ (flopDem βŠ™ β„‚.id-to-iso A B βŠ™ f βŠ™ flipDem) x β‰‘βŸ¨ cong (Ξ» Ο† β†’ Ο† x) (cong (Ξ» Ο† β†’ flopDem βŠ™ Ο† βŠ™ flipDem) recto-verso) ⟩ (flopDem βŠ™ flipDem) x β‰‘βŸ¨βŸ© x ∎) } h : Equivalence.Isomorphism (id-to-iso A B) h = ff , invv univalent : isEquiv (A ≑ B) (A β‰… B) (Univalence.id-to-iso (swap β„‚.isIdentity) A B) univalent = Equiv≃.fromIso _ _ h isCategory : IsCategory opRaw IsCategory.isAssociative isCategory = sym β„‚.isAssociative IsCategory.isIdentity isCategory = isIdentity IsCategory.arrowsAreSets isCategory = β„‚.arrowsAreSets IsCategory.univalent isCategory = univalent opposite : Category β„“a β„“b Category.raw opposite = opRaw Category.isCategory opposite = isCategory -- As demonstrated here a side-effect of having no-eta-equality on constructors -- means that we need to pick things apart to show that things are indeed -- definitionally equal. I.e; a thing that would normally be provable in one -- line now takes 13!! Admittedly it's a simple proof. module _ {β„‚ : Category β„“a β„“b} where open Category β„‚ private -- Since they really are definitionally equal we just need to pick apart -- the data-type. rawInv : Category.raw (opposite (opposite β„‚)) ≑ raw RawCategory.Object (rawInv _) = Object RawCategory.Arrow (rawInv _) = Arrow RawCategory.πŸ™ (rawInv _) = πŸ™ RawCategory._∘_ (rawInv _) = _∘_ oppositeIsInvolution : opposite (opposite β„‚) ≑ β„‚ oppositeIsInvolution = Category≑ rawInv open Opposite public