From 058f3c15a8de046fc44ba5cf3d4cac41bba634cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frederik=20Hangh=C3=B8j=20Iversen?= Date: Thu, 10 May 2018 15:28:33 +0200 Subject: [PATCH 01/33] Provide example of using pathJ --- doc/cubical.tex | 55 +++++++++++++++++++++++++++++++++++++------------ 1 file changed, 42 insertions(+), 13 deletions(-) diff --git a/doc/cubical.tex b/doc/cubical.tex index 43446cd..4284542 100644 --- a/doc/cubical.tex +++ b/doc/cubical.tex @@ -108,13 +108,10 @@ judgmentally $a$ at either endpoint. This is satisfied by the constant path; i.e. the path that stays at $a$ at any index $i$. It is also surpisingly easy to show functional extensionality with which we can -construct a path between $f$ and $g$ -- the function defined in the introduction -(section \S\ref{sec:functional-extensionality}). -%% module _ {ℓa ℓb} {A : Set ℓa} {B : A → Set ℓb} where -%% funExt : {f g : (x : A) → B x} → ((x : A) → f x ≡ g x) → f ≡ g -Functional extensionality is the proposition, given a type $A \tp \MCU$, a -family of types $B \tp A \to \MCU$ and functions $f, g \tp \prod_{a \tp A} -B\ a$: +construct a path between $f$ and $g$ -- the functions defined in the +introduction (section \S\ref{sec:functional-extensionality}). Functional +extensionality is the proposition, given a type $A \tp \MCU$, a family of types +$B \tp A \to \MCU$ and functions $f, g \tp \prod_{a \tp A} B\ a$: % \begin{equation} \label{eq:funExt} @@ -263,23 +260,55 @@ at some element $a \tp A$. Let a type $A \tp \MCU$ and an element of the type $a \tp A$ be given. $a$ is said to be the base of the induction. Given a family of types: % $$ -P \tp \prod_{a' \tp A} \prod_{p \tp a ≡ a'} \MCU +D \tp \prod_{b \tp A} \prod_{p \tp a ≡ b} \MCU $$ % -And an inhabitant of $P$ at $\refl$: +And an inhabitant of $D$ at $\refl$: % $$ -p \tp P\ a\ \refl +d \tp D\ a\ \refl $$ % We have the function: % \begin{equation} -\pathJ\ P\ p \tp \prod_{a' \tp A} \prod_{p \tp a ≡ a'} P\ a\ p +\pathJ\ D\ d \tp \prod_{b \tp A} \prod_{p \tp a ≡ b} D\ a\ p \end{equation} % -I will not give an example of using $\pathJ$ here. An application can be found -later in \ref{eq:pathJ-example}. +A simple application of $\pathJ$ is for proving that $\var{sym}$ is an +involution. Namely for any set $A \tp \MCU$, points $a, b \tp A$ and a path +between them $p \tp a \equiv b$: +% +\begin{equation} +\label{eq:sym-invol} +\var{sym}\ (\var{sym}\ p) ≡ p +\end{equation} +% +The proof will be by induction on $p$ and will be based at $a$. That is, $D$ +will be the family: +% +\begin{align*} +D & \tp \prod_{b' \tp A} \prod_{p \tp a ≡ b'ma} \MCU \\ +D\ b'\ p' & \defeq \var{sym}\ (\var{sym}\ p') ≡ p' +\end{align*} +% +The base-case will then be: +% +\begin{align*} +d & \tp \var{sym}\ (\var{sym}\ \refl) ≡ \refl \\ +d & \defeq \refl +\end{align*} +% +The reason $\refl$ proves this is that $\var{sym}\ \refl = \refl$ holds +definitionally. In summary \ref{eq:sym-invol} is inhabited by the term: +% +\begin{align*} + \pathJ\ (λ\ b'\ p' → \var{sym}\ (\var{sym}\ p') ≡ p')\ \var{refl}\ b\ p + \tp + \var{sym}\ (\var{sym}\ p) ≡ p +\end{align*} +% +We shall see another application on path-induction in \ref{eq:pathJ-example}. \subsection{Paths over propositions} \label{sec:lemPropF} From 30cf0bb765bfcc8b20ba365e6aac5054205827e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frederik=20Hangh=C3=B8j=20Iversen?= Date: Fri, 11 May 2018 13:07:47 +0200 Subject: [PATCH 02/33] Add additional example of pathJ --- doc/cubical.tex | 38 ++++++++++++++++++++++++++++++++++++-- doc/macros.tex | 3 ++- 2 files changed, 38 insertions(+), 3 deletions(-) diff --git a/doc/cubical.tex b/doc/cubical.tex index 4284542..e269451 100644 --- a/doc/cubical.tex +++ b/doc/cubical.tex @@ -288,7 +288,7 @@ The proof will be by induction on $p$ and will be based at $a$. That is, $D$ will be the family: % \begin{align*} -D & \tp \prod_{b' \tp A} \prod_{p \tp a ≡ b'ma} \MCU \\ +D & \tp \prod_{b' \tp A} \prod_{p \tp a ≡ b'} \MCU \\ D\ b'\ p' & \defeq \var{sym}\ (\var{sym}\ p') ≡ p' \end{align*} % @@ -303,11 +303,45 @@ The reason $\refl$ proves this is that $\var{sym}\ \refl = \refl$ holds definitionally. In summary \ref{eq:sym-invol} is inhabited by the term: % \begin{align*} - \pathJ\ (λ\ b'\ p' → \var{sym}\ (\var{sym}\ p') ≡ p')\ \var{refl}\ b\ p + \pathJ\ D\ d\ b\ p \tp \var{sym}\ (\var{sym}\ p) ≡ p \end{align*} % +Another application of $\pathJ$ is for proving associativity of $\trans$. That +is, given a type $A \tp \MCU$, elements of $A$, $a, b, c, d \tp A$ and paths +between them, $p \tp a \equiv b$, $q \tp b \equiv c$ and $r \tp c \equiv d$ we +have the following: +% +\begin{equation} + \label{eq:cum-trans} + \trans\ p\ (\trans\ q\ r) ≡ \trans\ (\trans\ p\ q)\ r +\end{equation} +% +In this case the induction will be based at $c$ (the left-endpoint of $r$) and +over the family: +% +\begin{align*} + T & \tp \prod_{d' \tp A} \prod_{r' \tp c ≡ d'} \MCU \\ + T\ d'\ r' & \defeq \trans\ p\ (\trans\ q\ r') ≡ \trans\ (\trans\ p\ q)\ r' +\end{align*} +% +So the base-case is proven with $t$ which is defined as: +% +\begin{align*} + \trans\ p\ (\trans\ q\ \refl) & ≡ + \trans\ p\ q \\ + & ≡ + \trans\ (\trans\ p\ q)\ \refl +\end{align*} +% +Here we have used the proposition $\trans\ p\ \refl \equiv p$ without proof. In +conclusion \ref{eq:cum-trans} is inhabited by the term: +% +\begin{align*} +\pathJ\ T\ t\ d\ r +\end{align*} +% We shall see another application on path-induction in \ref{eq:pathJ-example}. \subsection{Paths over propositions} diff --git a/doc/macros.tex b/doc/macros.tex index 1733db4..407eca0 100644 --- a/doc/macros.tex +++ b/doc/macros.tex @@ -91,4 +91,5 @@ \newcommand\Endo[1]{\varindex{Endo}\ #1} \newcommand\EndoR{\mathcal{R}} \newcommand\funExt{\varindex{funExt}} -\newcommand{\suc}[1]{\mathit{suc}\ #1} +\newcommand{\suc}[1]{\varindex{suc}\ #1} +\newcommand{\trans}{\varindex{trans}} From 4d73514ab51e90841d0293b5fa5e62ce9f3f2202 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frederik=20Hangh=C3=B8j=20Iversen?= Date: Fri, 11 May 2018 13:20:03 +0200 Subject: [PATCH 03/33] Use long name --- src/Cat.agda | 4 +- src/Cat/Category/Monad.agda | 233 ++++++++++++++------------ src/Cat/Category/Monad/Monoidal.agda | 65 ++++--- src/Cat/Category/Monad/Voevodsky.agda | 2 + 4 files changed, 162 insertions(+), 142 deletions(-) diff --git a/src/Cat.agda b/src/Cat.agda index 80d101d..fca9c99 100644 --- a/src/Cat.agda +++ b/src/Cat.agda @@ -10,8 +10,8 @@ open import Cat.Category.NaturalTransformation open import Cat.Category.Yoneda open import Cat.Category.Monoid open import Cat.Category.Monad -open Cat.Category.Monad.Monoidal -open Cat.Category.Monad.Kleisli +open import Cat.Category.Monad.Monoidal +open import Cat.Category.Monad.Kleisli open import Cat.Category.Monad.Voevodsky open import Cat.Categories.Sets diff --git a/src/Cat/Category/Monad.agda b/src/Cat/Category/Monad.agda index 8d5abc6..dc89634 100644 --- a/src/Cat/Category/Monad.agda +++ b/src/Cat/Category/Monad.agda @@ -28,186 +28,205 @@ import Cat.Category.Monad.Monoidal import Cat.Category.Monad.Kleisli open import Cat.Categories.Fun -module Monoidal = Cat.Category.Monad.Monoidal -module Kleisli = Cat.Category.Monad.Kleisli - -- | The monoidal- and kleisli presentation of monads are equivalent. module _ {ℓa ℓb : Level} (ℂ : Category ℓa ℓb) where open Cat.Category.NaturalTransformation ℂ ℂ using (NaturalTransformation ; propIsNatural) private module ℂ = Category ℂ open ℂ using (Object ; Arrow ; identity ; _<<<_ ; _>>>_) - module M = Monoidal ℂ - module K = Kleisli ℂ - module _ (m : M.RawMonad) where - open M.RawMonad m + module Monoidal = Cat.Category.Monad.Monoidal ℂ + module Kleisli = Cat.Category.Monad.Kleisli ℂ - forthRaw : K.RawMonad - K.RawMonad.omap forthRaw = Romap - K.RawMonad.pure forthRaw = pureT _ - K.RawMonad.bind forthRaw = bind + module _ (m : Monoidal.RawMonad) where + open Monoidal.RawMonad m - module _ {raw : M.RawMonad} (m : M.IsMonad raw) where - private - module MI = M.IsMonad m - forthIsMonad : K.IsMonad (forthRaw raw) - K.IsMonad.isIdentity forthIsMonad = snd MI.isInverse - K.IsMonad.isNatural forthIsMonad = MI.isNatural - K.IsMonad.isDistributive forthIsMonad = MI.isDistributive + toKleisliRaw : Kleisli.RawMonad + Kleisli.RawMonad.omap toKleisliRaw = Romap + Kleisli.RawMonad.pure toKleisliRaw = pure + Kleisli.RawMonad.bind toKleisliRaw = bind - forth : M.Monad → K.Monad - Kleisli.Monad.raw (forth m) = forthRaw (M.Monad.raw m) - Kleisli.Monad.isMonad (forth m) = forthIsMonad (M.Monad.isMonad m) + module _ {raw : Monoidal.RawMonad} (m : Monoidal.IsMonad raw) where + open Monoidal.IsMonad m - module _ (m : K.Monad) where - open K.Monad m + open Kleisli.RawMonad (toKleisliRaw raw) using (_>=>_) + toKleisliIsMonad : Kleisli.IsMonad (toKleisliRaw raw) + Kleisli.IsMonad.isIdentity toKleisliIsMonad = begin + bind pure ≡⟨⟩ + join <<< (fmap pure) ≡⟨ snd isInverse ⟩ + identity ∎ + Kleisli.IsMonad.isNatural toKleisliIsMonad f = begin + pure >=> f ≡⟨⟩ + pure >>> bind f ≡⟨⟩ + bind f <<< pure ≡⟨⟩ + (join <<< fmap f) <<< pure ≡⟨ isNatural f ⟩ + f ∎ + Kleisli.IsMonad.isDistributive toKleisliIsMonad f g = begin + bind g >>> bind f ≡⟨⟩ + (join <<< fmap g) >>> (join <<< fmap f) ≡⟨ isDistributive f g ⟩ + bind (g >=> f) ∎ + -- Kleisli.IsMonad.isDistributive toKleisliIsMonad = isDistributive - backRaw : M.RawMonad - M.RawMonad.R backRaw = R - M.RawMonad.pureNT backRaw = pureNT - M.RawMonad.joinNT backRaw = joinNT + toKleisli : Monoidal.Monad → Kleisli.Monad + Kleisli.Monad.raw (toKleisli m) = toKleisliRaw (Monoidal.Monad.raw m) + Kleisli.Monad.isMonad (toKleisli m) = toKleisliIsMonad (Monoidal.Monad.isMonad m) - private - open M.RawMonad backRaw renaming - ( join to join* - ; pure to pure* - ; bind to bind* - ; fmap to fmap* - ) - module R = Functor (M.RawMonad.R backRaw) + module _ (m : Kleisli.Monad) where + open Kleisli.Monad m - backIsMonad : M.IsMonad backRaw - M.IsMonad.isAssociative backIsMonad = begin - join* <<< R.fmap join* ≡⟨⟩ + toMonoidalRaw : Monoidal.RawMonad + Monoidal.RawMonad.R toMonoidalRaw = R + Monoidal.RawMonad.pureNT toMonoidalRaw = pureNT + Monoidal.RawMonad.joinNT toMonoidalRaw = joinNT + + open Monoidal.RawMonad toMonoidalRaw renaming + ( join to join* + ; pure to pure* + ; bind to bind* + ; fmap to fmap* + ) using () + + toMonoidalIsMonad : Monoidal.IsMonad toMonoidalRaw + Monoidal.IsMonad.isAssociative toMonoidalIsMonad = begin + join* <<< fmap join* ≡⟨⟩ join <<< fmap join ≡⟨ isNaturalForeign ⟩ join <<< join ∎ - M.IsMonad.isInverse backIsMonad {X} = inv-l , inv-r + Monoidal.IsMonad.isInverse toMonoidalIsMonad {X} = inv-l , inv-r where inv-l = begin join <<< pure ≡⟨ fst isInverse ⟩ identity ∎ inv-r = begin - joinT X <<< R.fmap (pureT X) ≡⟨⟩ + join* <<< fmap* pure* ≡⟨⟩ join <<< fmap pure ≡⟨ snd isInverse ⟩ identity ∎ - back : K.Monad → M.Monad - Monoidal.Monad.raw (back m) = backRaw m - Monoidal.Monad.isMonad (back m) = backIsMonad m + toMonoidal : Kleisli.Monad → Monoidal.Monad + Monoidal.Monad.raw (toMonoidal m) = toMonoidalRaw m + Monoidal.Monad.isMonad (toMonoidal m) = toMonoidalIsMonad m - module _ (m : K.Monad) where + module _ (m : Kleisli.Monad) where private - open K.Monad m + open Kleisli.Monad m bindEq : ∀ {X Y} - → K.RawMonad.bind (forthRaw (backRaw m)) {X} {Y} - ≡ K.RawMonad.bind (K.Monad.raw m) - bindEq {X} {Y} = begin - K.RawMonad.bind (forthRaw (backRaw m)) ≡⟨⟩ - (λ f → join <<< fmap f) ≡⟨⟩ - (λ f → bind (f >>> pure) >>> bind identity) ≡⟨ funExt lem ⟩ - (λ f → bind f) ≡⟨⟩ - bind ∎ + → Kleisli.RawMonad.bind (toKleisliRaw (toMonoidalRaw m)) {X} {Y} + ≡ bind + bindEq {X} {Y} = funExt lem where lem : (f : Arrow X (omap Y)) → bind (f >>> pure) >>> bind identity ≡ bind f lem f = begin + join <<< fmap f + ≡⟨⟩ bind (f >>> pure) >>> bind identity ≡⟨ isDistributive _ _ ⟩ + bind ((f >>> pure) >=> identity) + ≡⟨⟩ bind ((f >>> pure) >>> bind identity) ≡⟨ cong bind ℂ.isAssociative ⟩ bind (f >>> (pure >>> bind identity)) + ≡⟨⟩ + bind (f >>> (pure >=> identity)) ≡⟨ cong (λ φ → bind (f >>> φ)) (isNatural _) ⟩ bind (f >>> identity) ≡⟨ cong bind ℂ.leftIdentity ⟩ bind f ∎ - forthRawEq : forthRaw (backRaw m) ≡ K.Monad.raw m - K.RawMonad.omap (forthRawEq _) = omap - K.RawMonad.pure (forthRawEq _) = pure - K.RawMonad.bind (forthRawEq i) = bindEq i + toKleisliRawEq : toKleisliRaw (toMonoidalRaw m) ≡ Kleisli.Monad.raw m + Kleisli.RawMonad.omap (toKleisliRawEq i) = (begin + Kleisli.RawMonad.omap (toKleisliRaw (toMonoidalRaw m)) ≡⟨⟩ + Monoidal.RawMonad.Romap (toMonoidalRaw m) ≡⟨⟩ + omap ∎ + ) i + Kleisli.RawMonad.pure (toKleisliRawEq i) = (begin + Kleisli.RawMonad.pure (toKleisliRaw (toMonoidalRaw m)) ≡⟨⟩ + Monoidal.RawMonad.pure (toMonoidalRaw m) ≡⟨⟩ + pure ∎ + ) i + Kleisli.RawMonad.bind (toKleisliRawEq i) = bindEq i - fortheq : (m : K.Monad) → forth (back m) ≡ m - fortheq m = K.Monad≡ (forthRawEq m) + toKleislieq : (m : Kleisli.Monad) → toKleisli (toMonoidal m) ≡ m + toKleislieq m = Kleisli.Monad≡ (toKleisliRawEq m) - module _ (m : M.Monad) where + module _ (m : Monoidal.Monad) where private - open M.Monad m - module KM = K.Monad (forth m) + open Monoidal.Monad m + -- module KM = Kleisli.Monad (toKleisli m) + open Kleisli.Monad (toKleisli m) renaming + ( bind to bind* ; omap to omap* ; join to join* + ; fmap to fmap* ; pure to pure* ; R to R*) + using () module R = Functor R - omapEq : KM.omap ≡ Romap + omapEq : omap* ≡ Romap omapEq = refl - bindEq : ∀ {X Y} {f : Arrow X (Romap Y)} → KM.bind f ≡ bind f + bindEq : ∀ {X Y} {f : Arrow X (Romap Y)} → bind* f ≡ bind f bindEq {X} {Y} {f} = begin - KM.bind f ≡⟨⟩ - joinT Y <<< fmap f ≡⟨⟩ - bind f ∎ + bind* f ≡⟨⟩ + join <<< fmap f ≡⟨⟩ + bind f ∎ - joinEq : ∀ {X} → KM.join ≡ joinT X + joinEq : ∀ {X} → join* ≡ joinT X joinEq {X} = begin - KM.join ≡⟨⟩ - KM.bind identity ≡⟨⟩ - bind identity ≡⟨⟩ - joinT X <<< fmap identity ≡⟨ cong (λ φ → _ <<< φ) R.isIdentity ⟩ - joinT X <<< identity ≡⟨ ℂ.rightIdentity ⟩ - joinT X ∎ + join* ≡⟨⟩ + bind* identity ≡⟨⟩ + bind identity ≡⟨⟩ + join <<< fmap identity ≡⟨ cong (λ φ → _ <<< φ) R.isIdentity ⟩ + join <<< identity ≡⟨ ℂ.rightIdentity ⟩ + join ∎ - fmapEq : ∀ {A B} → KM.fmap {A} {B} ≡ fmap + fmapEq : ∀ {A B} → fmap* {A} {B} ≡ fmap fmapEq {A} {B} = funExt (λ f → begin - KM.fmap f ≡⟨⟩ - KM.bind (f >>> KM.pure) ≡⟨⟩ - bind (f >>> pureT _) ≡⟨⟩ - fmap (f >>> pureT B) >>> joinT B ≡⟨⟩ - fmap (f >>> pureT B) >>> joinT B ≡⟨ cong (λ φ → φ >>> joinT B) R.isDistributive ⟩ - fmap f >>> fmap (pureT B) >>> joinT B ≡⟨ ℂ.isAssociative ⟩ - joinT B <<< fmap (pureT B) <<< fmap f ≡⟨ cong (λ φ → φ <<< fmap f) (snd isInverse) ⟩ - identity <<< fmap f ≡⟨ ℂ.leftIdentity ⟩ - fmap f ∎ + fmap* f ≡⟨⟩ + bind* (f >>> pure*) ≡⟨⟩ + bind (f >>> pure) ≡⟨⟩ + fmap (f >>> pure) >>> join ≡⟨⟩ + fmap (f >>> pure) >>> join ≡⟨ cong (λ φ → φ >>> joinT B) R.isDistributive ⟩ + fmap f >>> fmap pure >>> join ≡⟨ ℂ.isAssociative ⟩ + join <<< fmap pure <<< fmap f ≡⟨ cong (λ φ → φ <<< fmap f) (snd isInverse) ⟩ + identity <<< fmap f ≡⟨ ℂ.leftIdentity ⟩ + fmap f ∎ ) - rawEq : Functor.raw KM.R ≡ Functor.raw R + rawEq : Functor.raw R* ≡ Functor.raw R RawFunctor.omap (rawEq i) = omapEq i RawFunctor.fmap (rawEq i) = fmapEq i - Req : M.RawMonad.R (backRaw (forth m)) ≡ R + Req : Monoidal.RawMonad.R (toMonoidalRaw (toKleisli m)) ≡ R Req = Functor≡ rawEq - pureTEq : M.RawMonad.pureT (backRaw (forth m)) ≡ pureT + pureTEq : Monoidal.RawMonad.pureT (toMonoidalRaw (toKleisli m)) ≡ pureT pureTEq = funExt (λ X → refl) pureNTEq : (λ i → NaturalTransformation Functors.identity (Req i)) - [ M.RawMonad.pureNT (backRaw (forth m)) ≡ pureNT ] + [ Monoidal.RawMonad.pureNT (toMonoidalRaw (toKleisli m)) ≡ pureNT ] pureNTEq = lemSigP (λ i → propIsNatural Functors.identity (Req i)) _ _ pureTEq - joinTEq : M.RawMonad.joinT (backRaw (forth m)) ≡ joinT + joinTEq : Monoidal.RawMonad.joinT (toMonoidalRaw (toKleisli m)) ≡ joinT joinTEq = funExt (λ X → begin - M.RawMonad.joinT (backRaw (forth m)) X ≡⟨⟩ - KM.join ≡⟨⟩ - joinT X <<< fmap identity ≡⟨ cong (λ φ → joinT X <<< φ) R.isIdentity ⟩ - joinT X <<< identity ≡⟨ ℂ.rightIdentity ⟩ - joinT X ∎) + Monoidal.RawMonad.joinT (toMonoidalRaw (toKleisli m)) X ≡⟨⟩ + join* ≡⟨⟩ + join <<< fmap identity ≡⟨ cong (λ φ → join <<< φ) R.isIdentity ⟩ + join <<< identity ≡⟨ ℂ.rightIdentity ⟩ + join ∎) joinNTEq : (λ i → NaturalTransformation F[ Req i ∘ Req i ] (Req i)) - [ M.RawMonad.joinNT (backRaw (forth m)) ≡ joinNT ] + [ Monoidal.RawMonad.joinNT (toMonoidalRaw (toKleisli m)) ≡ joinNT ] joinNTEq = lemSigP (λ i → propIsNatural F[ Req i ∘ Req i ] (Req i)) _ _ joinTEq - backRawEq : backRaw (forth m) ≡ M.Monad.raw m - M.RawMonad.R (backRawEq i) = Req i - M.RawMonad.pureNT (backRawEq i) = pureNTEq i - M.RawMonad.joinNT (backRawEq i) = joinNTEq i + toMonoidalRawEq : toMonoidalRaw (toKleisli m) ≡ Monoidal.Monad.raw m + Monoidal.RawMonad.R (toMonoidalRawEq i) = Req i + Monoidal.RawMonad.pureNT (toMonoidalRawEq i) = pureNTEq i + Monoidal.RawMonad.joinNT (toMonoidalRawEq i) = joinNTEq i - backeq : (m : M.Monad) → back (forth m) ≡ m - backeq m = M.Monad≡ (backRawEq m) - - eqv : isEquiv M.Monad K.Monad forth - eqv = gradLemma forth back fortheq backeq + toMonoidaleq : (m : Monoidal.Monad) → toMonoidal (toKleisli m) ≡ m + toMonoidaleq m = Monoidal.Monad≡ (toMonoidalRawEq m) open import Cat.Equivalence - Monoidal≊Kleisli : M.Monad ≅ K.Monad - Monoidal≊Kleisli = forth , back , funExt backeq , funExt fortheq + Monoidal≊Kleisli : Monoidal.Monad ≅ Kleisli.Monad + Monoidal≊Kleisli = toKleisli , toMonoidal , funExt toMonoidaleq , funExt toKleislieq - Monoidal≡Kleisli : M.Monad ≡ K.Monad + Monoidal≡Kleisli : Monoidal.Monad ≡ Kleisli.Monad Monoidal≡Kleisli = isoToPath Monoidal≊Kleisli diff --git a/src/Cat/Category/Monad/Monoidal.agda b/src/Cat/Category/Monad/Monoidal.agda index f5b20ad..c8ce5f2 100644 --- a/src/Cat/Category/Monad/Monoidal.agda +++ b/src/Cat/Category/Monad/Monoidal.agda @@ -18,7 +18,7 @@ private open Category ℂ using (Object ; Arrow ; identity ; _<<<_) open import Cat.Category.NaturalTransformation ℂ ℂ - using (NaturalTransformation ; Transformation ; Natural) + using (NaturalTransformation ; Transformation ; Natural ; NaturalTransformation≡) record RawMonad : Set ℓ where field @@ -78,15 +78,39 @@ record IsMonad (raw : RawMonad) : Set ℓ where isNatural : IsNatural isNatural {X} {Y} f = begin - joinT Y <<< R.fmap f <<< pureT X ≡⟨ sym ℂ.isAssociative ⟩ - joinT Y <<< (R.fmap f <<< pureT X) ≡⟨ cong (λ φ → joinT Y <<< φ) (sym (pureN f)) ⟩ - joinT Y <<< (pureT (R.omap Y) <<< f) ≡⟨ ℂ.isAssociative ⟩ - joinT Y <<< pureT (R.omap Y) <<< f ≡⟨ cong (λ φ → φ <<< f) (fst isInverse) ⟩ - identity <<< f ≡⟨ ℂ.leftIdentity ⟩ - f ∎ + join <<< fmap f <<< pure ≡⟨ sym ℂ.isAssociative ⟩ + join <<< (fmap f <<< pure) ≡⟨ cong (λ φ → join <<< φ) (sym (pureN f)) ⟩ + join <<< (pure <<< f) ≡⟨ ℂ.isAssociative ⟩ + join <<< pure <<< f ≡⟨ cong (λ φ → φ <<< f) (fst isInverse) ⟩ + identity <<< f ≡⟨ ℂ.leftIdentity ⟩ + f ∎ isDistributive : IsDistributive - isDistributive {X} {Y} {Z} g f = sym aux + isDistributive {X} {Y} {Z} g f = begin + join <<< fmap g <<< (join <<< fmap f) + ≡⟨ Category.isAssociative ℂ ⟩ + join <<< fmap g <<< join <<< fmap f + ≡⟨ cong (_<<< fmap f) (sym ℂ.isAssociative) ⟩ + (join <<< (fmap g <<< join)) <<< fmap f + ≡⟨ cong (λ φ → φ <<< fmap f) (cong (_<<<_ join) (sym (joinN g))) ⟩ + (join <<< (join <<< R².fmap g)) <<< fmap f + ≡⟨ cong (_<<< fmap f) ℂ.isAssociative ⟩ + ((join <<< join) <<< R².fmap g) <<< fmap f + ≡⟨⟩ + join <<< join <<< R².fmap g <<< fmap f + ≡⟨ sym ℂ.isAssociative ⟩ + (join <<< join) <<< (R².fmap g <<< fmap f) + ≡⟨ cong (λ φ → φ <<< (R².fmap g <<< fmap f)) (sym isAssociative) ⟩ + (join <<< fmap join) <<< (R².fmap g <<< fmap f) + ≡⟨ sym ℂ.isAssociative ⟩ + join <<< (fmap join <<< (R².fmap g <<< fmap f)) + ≡⟨ cong (_<<<_ join) ℂ.isAssociative ⟩ + join <<< (fmap join <<< R².fmap g <<< fmap f) + ≡⟨⟩ + join <<< (fmap join <<< fmap (fmap g) <<< fmap f) + ≡⟨ cong (λ φ → join <<< φ) (sym distrib3) ⟩ + join <<< fmap (join <<< fmap g <<< f) + ∎ where module R² = Functor F[ R ∘ R ] distrib3 : ∀ {A B C D} {a : Arrow C D} {b : Arrow B C} {c : Arrow A B} @@ -96,31 +120,6 @@ record IsMonad (raw : RawMonad) : Set ℓ where R.fmap (a <<< b <<< c) ≡⟨ R.isDistributive ⟩ R.fmap (a <<< b) <<< R.fmap c ≡⟨ cong (_<<< _) R.isDistributive ⟩ R.fmap a <<< R.fmap b <<< R.fmap c ∎ - aux = begin - joinT Z <<< R.fmap (joinT Z <<< R.fmap g <<< f) - ≡⟨ cong (λ φ → joinT Z <<< φ) distrib3 ⟩ - joinT Z <<< (R.fmap (joinT Z) <<< R.fmap (R.fmap g) <<< R.fmap f) - ≡⟨⟩ - joinT Z <<< (R.fmap (joinT Z) <<< R².fmap g <<< R.fmap f) - ≡⟨ cong (_<<<_ (joinT Z)) (sym ℂ.isAssociative) ⟩ - joinT Z <<< (R.fmap (joinT Z) <<< (R².fmap g <<< R.fmap f)) - ≡⟨ ℂ.isAssociative ⟩ - (joinT Z <<< R.fmap (joinT Z)) <<< (R².fmap g <<< R.fmap f) - ≡⟨ cong (λ φ → φ <<< (R².fmap g <<< R.fmap f)) isAssociative ⟩ - (joinT Z <<< joinT (R.omap Z)) <<< (R².fmap g <<< R.fmap f) - ≡⟨ ℂ.isAssociative ⟩ - joinT Z <<< joinT (R.omap Z) <<< R².fmap g <<< R.fmap f - ≡⟨⟩ - ((joinT Z <<< joinT (R.omap Z)) <<< R².fmap g) <<< R.fmap f - ≡⟨ cong (_<<< R.fmap f) (sym ℂ.isAssociative) ⟩ - (joinT Z <<< (joinT (R.omap Z) <<< R².fmap g)) <<< R.fmap f - ≡⟨ cong (λ φ → φ <<< R.fmap f) (cong (_<<<_ (joinT Z)) (joinN g)) ⟩ - (joinT Z <<< (R.fmap g <<< joinT Y)) <<< R.fmap f - ≡⟨ cong (_<<< R.fmap f) ℂ.isAssociative ⟩ - joinT Z <<< R.fmap g <<< joinT Y <<< R.fmap f - ≡⟨ sym (Category.isAssociative ℂ) ⟩ - joinT Z <<< R.fmap g <<< (joinT Y <<< R.fmap f) - ∎ record Monad : Set ℓ where field diff --git a/src/Cat/Category/Monad/Voevodsky.agda b/src/Cat/Category/Monad/Voevodsky.agda index abc8438..efdd6de 100644 --- a/src/Cat/Category/Monad/Voevodsky.agda +++ b/src/Cat/Category/Monad/Voevodsky.agda @@ -10,6 +10,8 @@ open import Cat.Category open import Cat.Category.Functor as F import Cat.Category.NaturalTransformation open import Cat.Category.Monad +import Cat.Category.Monad.Monoidal as Monoidal +import Cat.Category.Monad.Kleisli as Kleisli open import Cat.Categories.Fun open import Cat.Equivalence From aced19e99044af5342df3e445c491fd448b778da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frederik=20Hangh=C3=B8j=20Iversen?= Date: Tue, 15 May 2018 16:08:29 +0200 Subject: [PATCH 04/33] Various changes proposed by Andreas --- .gitignore | 1 + Makefile | 6 + doc/abstract.tex | 38 +++--- doc/conclusion.tex | 2 +- doc/cubical.tex | 59 ++++----- doc/halftime.tex | 4 +- doc/implementation.tex | 271 ++++++++++++++++++++++++++++++----------- doc/introduction.tex | 126 +++++++++++-------- doc/macros.tex | 7 +- doc/packages.tex | 1 + 10 files changed, 343 insertions(+), 172 deletions(-) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5ccff1a --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +html/ diff --git a/Makefile b/Makefile index 1a3e6e8..9d0744c 100644 --- a/Makefile +++ b/Makefile @@ -3,3 +3,9 @@ build: src/**.agda clean: find src -name "*.agdai" -type f -delete + +html: + agda --html src/Cat.agda + +upload: html + scp -r html/ remote11.chalmers.se:www/cat/doc/ diff --git a/doc/abstract.tex b/doc/abstract.tex index 04e47d7..e2bb834 100644 --- a/doc/abstract.tex +++ b/doc/abstract.tex @@ -1,21 +1,23 @@ \chapter*{Abstract} -The usual notion of propositional equality in intensional type-theory is -restrictive. For instance it does not admit functional extensionality or -univalence. This poses a severe limitation on both what is \emph{provable} and -the \emph{re-usability} of proofs. Recent developments have, however, resulted -in cubical type theory which permits a constructive proof of these two important -notions. The programming language Agda has been extended with capabilities for -working in such a cubical setting. This thesis will explore the usefulness of -this extension in the context of category theory. +The usual notion of propositional equality in intensional type-theory +is restrictive. For instance it does not admit functional +extensionality or univalence. This poses a severe limitation on both +what is \emph{provable} and the \emph{re-usability} of proofs. Recent +developments have, however, resulted in cubical type theory which +permits a constructive proof of these two important notions. The +programming language Agda has been extended with capabilities for +working in such a cubical setting. This thesis will explore the +usefulness of this extension in the context of category theory. -The thesis will motivate and explain why propositional equality in cubical Agda -is more expressive than in standard Agda. Alternative approaches to Cubical Agda -will be presented and their pros and cons will be explained. It will emphasize -why it is useful to have a constructive interpretation of univalence. As an -example of this two formulations of monads will be presented: Namely monaeds in -the monoidal form an monads in the Kleisli form. +The thesis will motivate and explain why propositional equality in +cubical Agda is more expressive than in standard Agda. Alternative +approaches to Cubical Agda will be presented and their pros and cons +will be explained. It will emphasize why it is useful to have a +constructive interpretation of univalence. As an example of this two +formulations of monads will be presented: Namely monads in the +monoidal form and monads in the Kleisli form. -Finally the thesis will explain the challenges that a developer will face when -working with cubical Agda and give some techniques to overcome these -difficulties. It will also try to suggest how furhter work can help allievate -some of these challenges. +Finally the thesis will explain the challenges that a developer will +face when working with cubical Agda and give some techniques to +overcome these difficulties. It will also try to suggest how further +work can help alleviate some of these challenges. diff --git a/doc/conclusion.tex b/doc/conclusion.tex index d2cfd0b..101a94f 100644 --- a/doc/conclusion.tex +++ b/doc/conclusion.tex @@ -9,7 +9,7 @@ admissible. Cubical Agda is more expressive, but there are certain issues that arise that are not present in standard Agda. For one thing ITT and standard Agda enjoys Uniqueness of Identity Proofs (UIP). This is not the case in Cubical Agda. In stead there exists a hierarchy of types with increasing -\nomen{homotopical structure}. It turns out to be useful to built the +\nomen{homotopical structure}{homotopy levels}. It turns out to be useful to built the formalization with this hierarchy in mind as it can simplify proofs considerably. Another issue one must overcome in Cubical Agda is when a type has a field whose type depends on a previous field. In this case paths between such diff --git a/doc/cubical.tex b/doc/cubical.tex index e269451..a5d8135 100644 --- a/doc/cubical.tex +++ b/doc/cubical.tex @@ -1,13 +1,13 @@ \chapter{Cubical Agda} \section{Propositional equality} -Judgmental equality in Agda is a feature of the type-system. Its something that -can be checked automatically by the type-checker: In the example from the +Judgmental equality in Agda is a feature of the type system. Its something that +can be checked automatically by the type checker: In the example from the introduction $n + 0$ can be judged to be equal to $n$ simply by expanding the definition of $+$. On the other hand, propositional equality is something defined within the language itself. Propositional equality cannot be derived automatically. The -normal definition of judgmental equality is an inductive data-type. Cubical Agda +normal definition of judgmental equality is an inductive data type. Cubical Agda discards this type in favor of a new primitives that has certain computational properties exclusive to it. @@ -22,15 +22,13 @@ two points of $A$; $a_0, a_1 \tp A$ we can form the type: a_0 \equiv a_1 \tp \MCU \end{align} % -In Agda this is defined as an inductive data-type with the single constructor +In Agda this is defined as an inductive data type with the single constructor for any $a \tp A$: % \begin{align} \refl \tp a \equiv a \end{align} % -For any $a \tp A$. - There also exist a related notion of \emph{heterogeneous} equality which allows for equating points of different types. In this case given two types $A, B \tp \MCU$ and two points $a \tp A$, $b \tp B$ we can construct the type: @@ -39,7 +37,7 @@ for equating points of different types. In this case given two types $A, B \tp a \cong b \tp \MCU \end{align} % -This is likewise defined as an inductive data-type with a single constructors +This is likewise defined as an inductive data type with a single constructors for any $a \tp A$: % \begin{align} @@ -56,17 +54,17 @@ Judgmental equality in Cubical Agda is encapsulated with the type: \Path \tp (P \tp I → \MCU) → P\ 0 → P\ 1 → \MCU \end{equation} % -$I$ is a special data-type (\TODO{that also has special computational properties +$I$ is a special data type (\TODO{that also has special computational properties AFAIK}) called the index set. $I$ can be thought of simply as the interval on the real numbers from $0$ to $1$. $P$ is a family of types over the index set -$I$. I will sometimes refer to $P$ as the ``path-space'' of some path $p \tp +$I$. I will sometimes refer to $P$ as the \nomenindex{path space} of some path $p \tp \Path\ P\ a\ b$. By this token $P\ 0$ then corresponds to the type at the left-endpoint and $P\ 1$ as the type at the right-endpoint. The type is called $\Path$ because it is connected with paths in homotopy theory. The intuition behind this is that $\Path$ describes paths in $\MCU$ -- i.e. between types. For a path $p$ for the point $p\ i$ the index $i$ describes how far along the path one has moved. An inhabitant of $\Path\ P\ a_0\ a_1$ is a (dependent-) function, -$p$, from the index-space to the path-space: +$p$, from the index-space to the path space: % $$ p \tp \prod_{i \tp I} P\ i @@ -80,16 +78,17 @@ endpoints. I.e.: p\ 1 & = a_1 \end{align*} % -The notion of ``homogeneous equalities'' is recovered when $P$ does not depend -on its argument: +The notion of \nomenindex{homogeneous equalities} is recovered when $P$ does not +depend on its argument. That is for $A \tp \MCU$, $a_0, a_1 \tp A$ the +homogenous equality between $a_0$ and $a_1$ is the type: % $$ a_0 \equiv a_1 \defeq \Path\ (\lambda i \to A)\ a_0\ a_1 $$ % -For $A \tp \MCU$, $a_0, a_1 \tp A$. I will generally prefer to use the notation +I will generally prefer to use the notation $a \equiv b$ when talking about non-dependent paths and use the notation -$\Path\ (\lambda i \to P\ i)\ a\ b$ when the path-space is of particular +$\Path\ (\lambda i \to P\ i)\ a\ b$ when the path space is of particular interest. With this definition we can also recover reflexivity. That is, for any $A \tp @@ -102,7 +101,7 @@ With this definition we can also recover reflexivity. That is, for any $A \tp \end{aligned} \end{equation} % -Here the path-space is $P \defeq \lambda i \to A$ and it satsifies $P\ i = A$ +Here the path space is $P \defeq \lambda i \to A$ and it satsifies $P\ i = A$ definitionally. So to inhabit it, is to give a path $I \to A$ which is judgmentally $a$ at either endpoint. This is satisfied by the constant path; i.e. the path that stays at $a$ at any index $i$. @@ -143,11 +142,12 @@ With this we can now prove the desired equality $f \equiv g$ from section % Paths have some other important properties, but they are not the focus of this thesis. \TODO{Refer the reader somewhere for more info.} +% \section{Homotopy levels} In ITT all equality proofs are identical (in a closed context). This means that, in some sense, any two inhabitants of $a \equiv b$ are ``equally good'' -- they do not have any interesting structure. This is referred to as Uniqueness of -Identity Proofs (UIP). Unfortunately it is not possible to have a type-theory +Identity Proofs (UIP). Unfortunately it is not possible to have a type theory with both univalence and UIP. In stead we have a hierarchy of types with an increasing amount of homotopic structure. At the bottom of this hierarchy we have the set of contractible types: @@ -162,7 +162,7 @@ have the set of contractible types: \end{equation} % The first component of $\isContr\ A$ is called ``the center of contraction''. -Under the propositions-as-types interpretation of type-theory $\isContr\ A$ can +Under the propositions-as-types interpretation of type theory $\isContr\ A$ can be thought of as ``the true proposition $A$''. And indeed $\top$ is contractible: \begin{equation*} @@ -181,7 +181,7 @@ The next step in the hierarchy is the set of mere propositions: \end{aligned} \end{equation} % -$\isProp\ A$ can be thought of as the set of true and false propositions. And +One can think of $\isProp\ A$ as the set of true and false propositions. And indeed both $\top$ and $\bot$ are propositions: % \begin{align*} @@ -189,9 +189,9 @@ indeed both $\top$ and $\bot$ are propositions: λ\varnothing\ \varnothing & \tp \isProp\ ⊥ \end{align*} % -$\varnothing$ is used here to denote an impossible pattern. It is a theorem that -if a mere proposition $A$ is inhabited, then so is it contractible. If it is not -inhabited it is equivalent to the empty-type (or false +The term $\varnothing$ is used here to denote an impossible pattern. It is a +theorem that if a mere proposition $A$ is inhabited, then so is it contractible. +If it is not inhabited it is equivalent to the empty-type (or false proposition).\TODO{Cite!!} I will refer to a type $A \tp \MCU$ as a \emph{mere} proposition if I want to @@ -225,8 +225,9 @@ As the reader may have guessed the next step in the hierarchy is the type: % And so it continues. In fact we can generalize this family of types by indexing them with a natural number. For historical reasons, though, the bottom of the -hierarchy, the contractible types, is said to be a \nomen{-2-type}, propositions -are \nomen{-1-types}, (homotopical) sets are \nomen{0-types} and so on\ldots +hierarchy, the contractible types, is said to be a \nomen{-2-type}{homotopy + levels}, propositions are \nomen{-1-types}{homotopy levels}, (homotopical) +sets are \nomen{0-types}{homotopy levels} and so on\ldots Just as with paths, homotopical sets are not at the center of focus for this thesis. But I mention here some properties that will be relevant for this @@ -253,8 +254,8 @@ of these theorems here, as they will be used later in chapter \subsection{Path induction} \label{sec:pathJ} The induction principle for paths intuitively gives us a way to reason about a -type-family indexed by a path by only considering if said path is $\refl$ (the -``base-case''). For \emph{based path induction}, that equality is \emph{based} +type family indexed by a path by only considering if said path is $\refl$ (the +\nomen{base case}{path induction}). For \emph{based path induction}, that equality is \emph{based} at some element $a \tp A$. Let a type $A \tp \MCU$ and an element of the type $a \tp A$ be given. $a$ is said to be the base of the induction. Given a family of types: @@ -292,7 +293,7 @@ D & \tp \prod_{b' \tp A} \prod_{p \tp a ≡ b'} \MCU \\ D\ b'\ p' & \defeq \var{sym}\ (\var{sym}\ p') ≡ p' \end{align*} % -The base-case will then be: +The base case will then be: % \begin{align*} d & \tp \var{sym}\ (\var{sym}\ \refl) ≡ \refl \\ @@ -326,7 +327,7 @@ over the family: T\ d'\ r' & \defeq \trans\ p\ (\trans\ q\ r') ≡ \trans\ (\trans\ p\ q)\ r' \end{align*} % -So the base-case is proven with $t$ which is defined as: +So the base case is proven with $t$ which is defined as: % \begin{align*} \trans\ p\ (\trans\ q\ \refl) & ≡ @@ -342,7 +343,7 @@ conclusion \ref{eq:cum-trans} is inhabited by the term: \pathJ\ T\ t\ d\ r \end{align*} % -We shall see another application on path-induction in \ref{eq:pathJ-example}. +We shall see another application on path induction in \ref{eq:pathJ-example}. \subsection{Paths over propositions} \label{sec:lemPropF} @@ -357,7 +358,7 @@ a heterogeneous path between any two elements of $p_0 \tp P\ a_0$ and $p_1 \tp P\ a_1$: % $$ -\lemPropF\ \var{propP}\ p \defeq \Path\ (\lambda\; i \mto P\ (p\ i))\ p_0\ p_1 +\lemPropF\ \var{propP}\ p \tp \Path\ (\lambda\; i \mto P\ (p\ i))\ p_0\ p_1 $$ % This is quite a mouthful. So let me try to show how this is a very general and diff --git a/doc/halftime.tex b/doc/halftime.tex index 8381f2b..ca6d9a9 100644 --- a/doc/halftime.tex +++ b/doc/halftime.tex @@ -57,8 +57,8 @@ composition and identity, laws; preservation of identity and composition) plus the extra condition that it is univalent - namely that you can get an equality of two objects from an isomorphism. -I make no distinction between a pre-category and a real category (as in the -[HoTT]-sense). A pre-category in my implementation would be a category sans the +I make no distinction between a pre category and a real category (as in the +[HoTT]-sense). A pre category in my implementation would be a category sans the witness to univalence. I also prove that being a category is a proposition. This gives rise to an diff --git a/doc/implementation.tex b/doc/implementation.tex index 93c404e..d94f033 100644 --- a/doc/implementation.tex +++ b/doc/implementation.tex @@ -2,33 +2,44 @@ \label{ch:implementation} This implementation formalizes the following concepts: % -\begin{enumerate}[i.] -\item Categories -\item Functors -\item Products -\item Exponentials -\item Cartesian closed categories -\item Natural transformations -\item Yoneda embedding -\item Monads -\item Categories - \begin{enumerate}[i.] - \item Opposite category - \item Category of sets - \item ``Pair category'' - \end{enumerate} -\end{enumerate} +\newcommand{\sourcebasepath}{http://web.student.chalmers.se/~hanghj/cat/doc/html/} +\newcommand{\sourcelink}[1]{\href{\sourcebasepath#1.html}{\texttt{#1}}} +\begin{center} +\begin{tabular}{ l l } +Name & Link \\ +\hline +Categories & \sourcelink{Cat.Category} \\ +Functors & \sourcelink{Cat.Category.Functor} \\ +Products & \sourcelink{Cat.Category.Products} \\ +Exponentials & \sourcelink{Cat.Category.Exponentials} \\ +Cartesian closed categories & \sourcelink{Cat.Category.CartesianClosed} \\ +Natural transformations & \sourcelink{Cat.Category.NaturalTransformation} \\ +Yoneda embedding & \sourcelink{Cat.Category.Yoneda} \\ +Monads & \sourcelink{Cat.Category.Monads} \\ +%% Categories & \null \\ +%% +Opposite category & +\href{\sourcebasepath Cat.Category.html#22744}{\texttt{Cat.Category.Opposite}} \\ +Category of sets & \sourcelink{Cat.Categories.Sets} \\ +Span category & +\href{\sourcebasepath Cat.Category.Product.html#2919}{\texttt{Cat.Category.Product.Span}} \\ + %% +\end{tabular} +\end{center} % Furthermore the following items have been partly formalized: % -\begin{enumerate}[i.] -\item The (higher) category of categories. -\item Category of relations -\item Category of functors and natural transformations -- only as a precategory -\item Free category -\item Monoidal objects -\item Monoidal categories -\end{enumerate} +\begin{center} +\begin{tabular}{ l l } +Name & Link \\ +\hline +Category of categories & \sourcelink{Cat.Categories.Cat} \\ +Category of relations & \sourcelink{Cat.Categories.Rel} \\ +Category of functors & \sourcelink{Cat.Categories.Fun} \\ +Free category & \sourcelink{Cat.Categories.Free} \\ +Monoids & \sourcelink{Cat.Category.Monoid} \\ +\end{tabular} +\end{center} % As well as a range of various results about these. E.g. I have shown that the category of sets has products. In the following I aim to demonstrate some of the @@ -70,22 +81,22 @@ constituents of a category and can be found in typical mathematical expositions on the topic. We, however, impose one further requirement on what it means to be a category, namely that the type of arrows form a set. -Such categories are called \nomen{1-categories}. It is possible to relax this -requirement. This would lead to the notion of higher categories (\cite[p. +Such categories are called \nomen{1-categories}{1-category}. It is possible to relax +this requirement. This would lead to the notion of higher categories (\cite[p. 307]{hott-2013}). For the purpose of this project, however, this report will -restrict itself to 1-categories. Making based on higher categories would be a -very natural possible extension of this work. +restrict itself to 1-categories\index{1-category}. Generalizing this work to +higher categories would be a very natural possible extension of this work. Raw categories satisfying all of the above requirements are called a -\nomen{pre}-categories. As a further requirement to be a proper category we +\nomenindex{pre categories}. As a further requirement to be a proper category we require it to be univalent. Before we can define this, I must introduce two more definitions: If we let $p$ be a witness to the identity law, which formally is: % \begin{equation} \label{eq:identity} \var{IsIdentity} \defeq - \prod_{A\ B \tp \Object} \prod_{f \tp A \to B} - \id \comp f \equiv f \x f \comp \id \equiv f + \prod_{A\ B \tp \Object} \prod_{f \tp \Arrow\ A\ B} + \id \lll f \equiv f \x f \lll \id \equiv f \end{equation} % Then we can construct the identity isomorphism $\idIso \tp \identity, @@ -190,8 +201,8 @@ This example illustrates nicely how we can use these combinators to reason about the other homotopic levels. These combinators are however not applicable in situations where we want to reason about other types - e.g. types we have defined ourselves. For instance, after we have proven that all the projections -of pre-categories are propositions, then we would like to bundle this up to show -that the type of pre-categories is also a proposition. Formally: +of pre categories are propositions, then we would like to bundle this up to show +that the type of pre categories is also a proposition. Formally: % \begin{equation} \label{eq:propIsPreCategory} @@ -264,7 +275,7 @@ a priori that equality proofs are unique. The situation is a bit more complicated when we have a dependent type. For instance, when we want to show that $\IsCategory$ is a mere proposition. -$\IsCategory$ is a record with two fields, a witness to being a pre-category and +$\IsCategory$ is a record with two fields, a witness to being a pre category and the univalence condition. Recall that the univalence condition is indexed by the identity-proof. So to follow the same recipe as above, let $a\ b \tp \IsCategory$ be given, to show them equal, we now need to give two paths. One homogeneous: @@ -423,7 +434,7 @@ equalities and isomorphisms (on arrows). It is worthwhile to dwell on this for a few seconds. This type looks very similar to univalence for types and is therefore perhaps a bit more intuitive to grasp the implications of. Of course univalence for types (which is a proposition -- i.e. provable) does not imply -univalence of all pre-category since morphisms in a category are not regular +univalence of all pre category since morphisms in a category are not regular functions -- in stead they can be thought of as a generalization hereof. The univalence criterion therefore is simply a way of restricting arrows to behave similarly to maps. @@ -541,7 +552,7 @@ over-bar. So e.g. $\idToIso$ is a function in the underlying category and the corresponding thing is denoted $\wideoverbar{\idToIso}$ in the opposite category. -Showing that this forms a pre-category is rather straightforward. +Showing that this forms a pre category is rather straightforward. % $$ h \rrr (g \rrr f) \equiv h \rrr g \rrr f @@ -826,13 +837,12 @@ that there exists a unique arrow $\pi \tp \Arrow\ X\ (A \x B)$ satisfying % $\pi$ is called the product (arrow) of $f$ and $g$. -\subsection{Pair category} +\subsection{Span category} \newcommand\pairA{\mathcal{A}} \newcommand\pairB{\mathcal{B}} Given a base category $\bC$ and two objects in this category $\pairA$ and -$\pairB$ we can construct the ``pair category'': \TODO{This is a working title, - it is nice to have a name for this thing to refer back to} +$\pairB$ we can construct the \nomenindex{span category}: The type of objects in this category will be an object in the underlying category, $X$, and two arrows (also from the underlying category) @@ -964,7 +974,7 @@ $$ This we get from \ref{eq:productEqPrinc} and the fact that homotopical structure is cumulative. -This finishes the proof that this is a valid pre-category. +This finishes the proof that this is a valid pre category. \subsubsection{Univalence} To prove that this is a proper category it must be shown that it is univalent. @@ -1151,9 +1161,10 @@ gory details. % \subsection{Propositionality of products} % -Now that we have constructed the ``pair category'' I will demonstrate how to use -this to prove that products are propositional. I will do this by showing that -terminal objects in this category are equivalent to products: +Now that we have constructed the span category\index{span category} I will + demonstrate how to use this to prove that products are propositional. I will + do this by showing that terminal objects in this category are equivalent to + products: % \begin{align} \var{Terminal} ≃ \var{Product}\ ℂ\ \mathcal{A}\ \mathcal{B} @@ -1178,7 +1189,7 @@ indeed a product. That is, for an object $Y$ and two arrows $y_𝒜 \tp % Since $X, x_𝒜, x_ℬ$ is a terminal object there is a \emph{unique} arrow from this object to any other object, so also $Y, y_𝒜, y_ℬ$ in particular (which is -also an object in the pair category). The arrow we will play the role of $f$ and +also an object in the span category). The arrow we will play the role of $f$ and it immediately satisfies \ref{eq:pairCondRev}. Any other arrow satisfying these conditions will be equal since $f$ is unique. @@ -1262,14 +1273,15 @@ Denote the arrow-map of $\EndoR$ as $\fmap$, then this data must satisfy the following laws: % \begin{align} -\label{eq:monad-monoidal-laws} -\begin{split} +\label{eq:monad-monoidal-laws-0} \join \lll \fmap\ \join - & ≡ \join \lll \join\ \fmap \\ - \join \lll \pure\ \fmap & ≡ \identity \\ + & ≡ \join \lll \join \\ +\label{eq:monad-monoidal-laws-1} + \join \lll \pure\ & ≡ \identity \\ +\label{eq:monad-monoidal-laws-2} \join \lll \fmap\ \pure & ≡ \identity -\end{split} \end{align} +\newcommand\monoidallaws{\ref{eq:monad-monoidal-laws-0}, \ref{eq:monad-monoidal-laws-1} and \ref{eq:monad-monoidal-laws-2}}% % The implicit arguments to the arrows above have been left out and the objects they range over are universally quantified. @@ -1279,13 +1291,13 @@ they range over are universally quantified. The Kleisli-formulation consists of the following data: % \begin{align} -\label{eq:monad-kleisli-data} \begin{split} - \EndoR & \tp \Object → \Object \\ - \pure & \tp % \prod_{X \tp Object} +\label{eq:monad-kleisli-data} +\EndoR & \tp \Object → \Object \\ +\pure & \tp % \prod_{X \tp Object} \Arrow\ X\ (\EndoR\ X) \\ \bind & \tp % \prod_{X\;Y \tp Object} → \Arrow\ X\ (\EndoR\ Y) - \Arrow\ (\EndoR\ X)\ (\EndoR\ Y) + \Arrow\ (\EndoR\ X)\ (\EndoR\ Y) \end{split} \end{align} % @@ -1298,17 +1310,14 @@ is a regular maps on objects and a pair of arrows. This data must satisfy: % \begin{align} -\label{eq:monad-monoidal-laws} -\begin{split} - \bind\ \pure & ≡ \identity_{\EndoR\ X} - \\ - % \prod_{f \tp \Arrow\ X\ (\EndoR\ Y)} - \pure \fish f & ≡ f - \\ - % \prod_{\substack{g \tp \Arrow\ Y\ (\EndoR\ Z)\\f \tp \Arrow\ X\ (\EndoR\ Y)}} +\label{eq:monad-kleisli-laws-0} +\bind\ \pure & ≡ \identity_{\EndoR\ X} \\ +\label{eq:monad-kleisli-laws-1} +\pure \fish f & ≡ f \\ +\label{eq:monad-kleisli-laws-2} (\bind\ f) \rrr (\bind\ g) & ≡ \bind\ (f \fish g) -\end{split} \end{align} +\newcommand\kleislilaws{\ref{eq:monad-kleisli-laws-0}, \ref{eq:monad-kleisli-laws-1} and \ref{eq:monad-kleisli-laws-2}}% % Here likewise the arrows $f \tp \Arrow\ X\ (\EndoR\ Y)$ and $g \tp \Arrow\ Y\ (\EndoR\ Z)$ are universally quantified (as well as the objects they @@ -1317,10 +1326,6 @@ f \rrr (\bind\ g)$ . (\TODO{Better way to typeset $\fish$?}) \subsection{Equivalence of formulations} % -In my implementation I proceed to show how the one formulation gives rise to -the other and vice-versa. For the present purpose I will briefly sketch some -parts of this construction: - The notation I have chosen here in the report overloads e.g. $\pure$ to both refer to a natural transformation and an arrow. This is of course not a coincidence as the arrow in the Kleisli formulation @@ -1329,15 +1334,141 @@ called $\pure$. In the monoidal formulation we can define $\bind$: % +\newcommand\joinX{\wideoverbar{\join}}% +\newcommand\bindX{\wideoverbar{\bind}}% +\newcommand\EndoRX{\wideoverbar{\EndoR}}% +\newcommand\pureX{\wideoverbar{\pure}}% +\newcommand\fmapX{\wideoverbar{\fmap}}% \begin{align} -\bind \defeq \join \lll \fmap\ f +\bind\ f \defeq \joinX \lll \fmap\ f \end{align} % And likewise in the Kleisli formulation we can define $\join$: % \begin{align} -\join \defeq \bind\ \identity +\join \defeq \bindX\ \identity \end{align} % -It now remains to show that we can prove the various laws given this choice. I -refer the reader to my implementation for the details. +Here $\joinX$ corresponds to the arrow from the natural +transformation $\join$. $\bindX$ on the other hand corresponds to a +natural transformation constructed from $\bind$. It now remains to show that +this construction indeed gives rise to a monad. This will be done in two steps. +First we will assume that we have a monad in the monoidal form; $(\EndoR, \pure, +\join)$ and then show that $\EndoR, \pure, \bind$ is indeed a monad in the +Kleisli form. In the second part we will show the other direction. + +\subsubsection{Monoidal to Kleisli} +Let $(\EndoR, \pure, \join)$ be given as in \ref{eq:monad-monoidal-data} +satisfying the laws \monoidallaws. For the data of the Kleisli +formulation we pick: +% +\begin{align} +\begin{split} + \EndoR & \defeq \EndoRX \\ + \pure & \defeq \pureX \\ + \bind\ f & \tp \joinX \lll \fmapX\ f +\end{split} +\end{align} +% +$\EndoRX$ is the object map of the endo-functor $\EndoR$, +$\pureX$ and $\joinX$ are the arrows from the natural +transformations $\pure$ and $\join$ respectively. $\fmapX$ is the +arrow map of the endo-functor $\EndoR$. It now just remains to verify +the laws \kleislilaws. For \ref{eq:monad-kleisli-laws-0}: +% +\begin{align*} +\bind\ \pure & ≡ +\join \lll (\fmap\ \pure) && \text{By definition} \\ +& ≡ \identity && \text{By \ref{eq:monad-monoidal-laws-2}} +\end{align*} +% +For \ref{eq:monad-kleisli-laws-1}: +% +\begin{align*} +\pure \fish f +& \equiv %%% +\pure \ggg \bind\ f && \text{By definition} \\ & ≡ +\bind\ f \lll \pure && \text{By definition} \\ & ≡ +\joinX \lll \fmapX\ f \lll \pureX && \text{By definition} \\ & ≡ +\joinX \lll \pureX \lll f && \text{$\pure$ is a natural transformation} \\ & ≡ +\identity \lll f && \text{By \ref{eq:monad-monoidal-laws-1}} \\ & ≡ +f && \text{Left identity} +\end{align*} +% +For \ref{eq:monad-kleisli-laws-2}: +\begin{align*} +\bind\ g \rrr \bind\ f & ≡ +\bind\ f \lll \bind\ g + \\ & ≡ +%% %%%% +\joinX \lll \fmapX\ g \lll \joinX \lll \fmapX\ f +&& \text{\dots} \\ & ≡ +\joinX \lll \joinX \lll \fmapX^2\ g \lll \fmapX\ f +&& \text{$\join$ is a natural transformation} \\ & ≡ +\joinX\ \lll \fmapX\ \joinX \lll \fmapX^2\ g \lll \fmapX\ f +&& \text{By \ref{eq:monad-monoidal-laws-0}} \\ & ≡ +\joinX\ \lll \fmapX\ \joinX\ \lll \fmapX\ (\fmapX\ g) \lll \fmapX\ f +&& \text{} \\ & ≡ +\joinX \lll \fmapX\ (\joinX \lll \fmapX\ g \lll f) +&& \text{Distributive law for functors} \\ & \equiv +%%%% +\bind\ (g \fish f) +\end{align*} +\subsubsection{Kleisli to Monoidal} +For the other direction we are given $(\EndoR, \pure, \bind)$ as in +\ref{eq:monad-kleisli-data} satisfying the laws \kleislilaws. For the data of +the monoidal formulation we pick: +% +\begin{align} +\begin{split} + \EndoR & \defeq \EndoRX \\ + \pure & \defeq \pureX \\ + \join & \defeq \bind\ \identity +\end{split} +\end{align} +% +Where $\EndoRX \defeq (\bind\ (\pure \lll f), \EndoR)$ and $\pureX \defeq +\bind\ \identity$. We must now show the laws \monoidallaws, but we must also +verify that our choice of $\EndoRX$ actually is a functor. I will ommit this +here. In stead we shall see how these two mappings are indeed inverses. + +\subsubsection{Equivalence} +To prove that the two formulations are equivalent we must demonstrate that the +two mappings sketched above are indeed inverses of each other. If we name the +first mapping $\toKleisli$ and it's proposed inverse $\toMonoidal$ +then we must show: +% +\begin{align} + \label{eq:monad-forwards} + \toKleisli \comp \toMonoidal & ≡ \identity \\ + \label{eq:monad-backwards} + \toMonoidal \comp \toKleisli & ≡ \identity +\end{align} +% +For \ref{eq:monad-forwards} let $(\EndoR, \pure, \join)$ be a monad in the +monoidal form. In my formulation the proof that being-a-monad is a proposition +can be found. With this result in place we get an equality principle for +kleisli-monads that say that to equate two such monads it suffices to equate +their data-part. So it suffices to equate the data-parts of the +\ref{eq:monad-forwards}. Such a proof is a triple equation the three projections +of \ref{eq:monad-kleisli-data}. The first two hold definitionally -- essentially +one just wraps and unwraps the morphism in a functor. For the last equation a +little more work is required: +% +\begin{align*} +\join \lll \fmap\ f & ≡ +\fmap\ f \rrr \join \\ & ≡ +\bind\ (f \rrr \pure) \rrr \bind\ \identity + && \text{By definition of $\fmap$ and $\join$} \\ & ≡ +\bind\ (f \rrr \pure \fish \identity) + && \text{By \ref{eq:monad-kleisli-laws-2}} \\ & ≡ +\bind\ (f \rrr \identity) + && \text{By \ref{eq:monad-kleisli-laws-1}} \\ & ≡ +\bind\ f +\end{align*} +% +For the other direction we can likewise verify that the maps $\EndoR$, $\bind$, +$\join$, and $\fmap$ are equal. The equality principle for functors gives us +that this is enough to show that the the functor $\EndoR$ we construct is +identical. Similarly for the natural transformations we have that the naturality +condition is a proposition so the paths between the maps are sufficient. diff --git a/doc/introduction.tex b/doc/introduction.tex index a3b5567..31a8ce3 100644 --- a/doc/introduction.tex +++ b/doc/introduction.tex @@ -9,19 +9,21 @@ limitations inherent in ITT and -- by extension -- Agda. Consider the functions: % \begin{multicols}{2} - \noindent - \begin{equation*} - f \defeq (n \tp \bN) \mto (0 + n \tp \bN) - \end{equation*} - \begin{equation*} - g \defeq (n \tp \bN) \mto (n + 0 \tp \bN) - \end{equation*} -\end{multicols} + \noindent% + \begin{equation*}% + f \defeq \lambda\ (n \tp \bN) \to (0 + n \tp \bN) + \end{equation*}% + \begin{equation*}% + g \defeq \lambda\ (n \tp \bN) \to (n + 0 \tp \bN) + \end{equation*}% +\end{multicols}% % -$n + 0$ is \nomen{definitionally} equal to $n$, which we write as $n + 0 = n$. -This is also called \nomen{judgmental} equality. We call it definitional -equality because the \emph{equality} arises from the \emph{definition} of $+$ -which is: +The term $n + 0$ is +\nomenindex{definitionally} equal to $n$, which we +write as $n + 0 = n$. This is also called +\nomenindex{judgmental equality}. +We call it definitional equality because the \emph{equality} arises +from the \emph{definition} of $+$ which is: % \begin{align*} + & \tp \bN \to \bN \to \bN \\ @@ -29,11 +31,12 @@ which is: n + (\suc{m}) & \defeq \suc{(n + m)} \end{align*} % -Note that $0 + n$ is \emph{not} definitionally equal to $n$. $0 + n$ is in -normal form. I.e.; there is no rule for $+$ whose left-hand-side matches this -expression. We \emph{do}, however, have that they are \nomen{propositionally} -equal, which we write as $n + 0 \equiv n$. Propositional equality means that -there is a proof that exhibits this relation. Since equality is a transitive +Note that $0 + n$ is \emph{not} definitionally equal to $n$. $0 + n$ +is in normal form. I.e.; there is no rule for $+$ whose left hand side +matches this expression. We \emph{do}, however, have that they are +\nomen{propositionally}{propositional equality} equal, which we write +as $n + 0 \equiv n$. Propositional equality means that there is a +proof that exhibits this relation. Since equality is a transitive relation we have that $n + 0 \equiv 0 + n$. Unfortunately we don't have $f \equiv g$.\footnote{Actually showing this is @@ -43,7 +46,8 @@ not true.} There is no way to construct a proof asserting the obvious equivalence of $f$ and $g$ -- even though we can prove them equal for all points. This is exactly the notion of equality of functions that we are interested in; that they are equal for all inputs. We call this -\nomen{point-wise equality}, where the \emph{points} of a function refers + +\nomenindex{point-wise equality}, where the \emph{points} of a function refers to its arguments. In the context of category theory functional extensionality is e.g. needed to @@ -51,14 +55,14 @@ show that representable functors are indeed functors. The representable functor for a category $\bC$ and a fixed object in $A \in \bC$ is defined to be: % \begin{align*} -\fmap \defeq X \mto \Hom_{\bC}(A, X) +\fmap \defeq \lambda\ X \to \Hom_{\bC}(A, X) \end{align*} % The proof obligation that this satisfies the identity law of functors ($\fmap\ \idFun \equiv \idFun$) thus becomes: % \begin{align*} -\Hom(A, \idFun_{\bX}) = (g \mto \idFun \comp g) \equiv \idFun_{\Sets} +\Hom(A, \idFun_{\bX}) = (\lambda\ g \to \idFun \comp g) \equiv \idFun_{\Sets} \end{align*} % One needs functional extensionality to ``go under'' the function arrow and apply @@ -67,20 +71,23 @@ the (left) identity law of the underlying category to prove $\idFun \comp g % \subsection{Equality of isomorphic types} % -Let $\top$ denote the unit type -- a type with a single constructor. In the -propositions-as-types interpretation of type theory $\top$ is the proposition -that is always true. The type $A \x \top$ and $A$ has an element for each $a : -A$. So in a sense they have the same shape (Greek; \nomen{isomorphic}). The -second element of the pair does not add any ``interesting information''. It can -be useful to identify such types. In fact, it is quite commonplace in -mathematics. Say we look at a set $\{x \mid \phi\ x \land \psi\ x\}$ and somehow -conclude that $\psi\ x \equiv \top$ for all $x$. A mathematician would -immediately conclude $\{x \mid \phi\ x \land \psi\ x\} \equiv \{x \mid -\phi\ x\}$ without thinking twice. Unfortunately such an identification can not +Let $\top$ denote the unit type -- a type with a single constructor. +In the propositions as types interpretation of type theory $\top$ is +the proposition that is always true. The type $A \x \top$ and $A$ has +an element for each $a \tp A$. So in a sense they have the same shape +(Greek; +\nomenindex{isomorphic}). The second element of the pair does not +add any ``interesting information''. It can be useful to identify such +types. In fact, it is quite commonplace in mathematics. Say we look at +a set $\{x \mid \phi\ x \land \psi\ x\}$ and somehow conclude that +$\psi\ x \equiv \top$ for all $x$. A mathematician would immediately +conclude $\{x \mid \phi\ x \land \psi\ x\} \equiv \{x \mid \phi\ x\}$ +without thinking twice. Unfortunately such an identification can not be performed in ITT. More specifically what we are interested in is a way of identifying -\nomen{equivalent} types. I will return to the definition of equivalence later + +\nomenindex{equivalent} types. I will return to the definition of equivalence later in section \S\ref{sec:equiv}, but for now it is sufficient to think of an equivalence as a one-to-one correspondence. We write $A \simeq B$ to assert that $A$ and $B$ are equivalent types. The principle of univalence says that: @@ -88,7 +95,7 @@ $A$ and $B$ are equivalent types. The principle of univalence says that: $$\mathit{univalence} \tp (A \simeq B) \simeq (A \equiv B)$$ % In particular this allows us to construct an equality from an equivalence -($\mathit{ua} \tp (A \simeq B) \to (A \equiv B)$) and vice-versa. +($\mathit{ua} \tp (A \simeq B) \to (A \equiv B)$) and vice versa. \section{Formalizing Category Theory} % @@ -127,7 +134,7 @@ implementations of category theory in Agda: \item \url{https://github.com/mortberg/cubicaltt} - A formalization in CubicalTT - a language designed for cubical-type-theory. + A formalization in CubicalTT - a language designed for cubical type theory. Formalizes many different things, but only a few concepts from category theory. @@ -141,19 +148,27 @@ compare some aspects of this formalization with the existing ones.\TODO{How can There are alternative approaches to working in a cubical setting where one can still have univalence and functional extensionality. One option is to postulate these as axioms. This approach, however, has other shortcomings, e.g.; you lose -\nomen{canonicity} (\TODO{Pageno!} \cite{huber-2016}). Canonicity means that any -well-typed term evaluates to a \emph{canonical} form. For example for a closed + +\nomenindex{canonicity} (\TODO{Pageno!} \cite{huber-2016}). Canonicity means that any +well typed term evaluates to a \emph{canonical} form. For example for a closed term $e \tp \bN$ it will be the case that $e$ reduces to $n$ applications of $\mathit{suc}$ to $0$ for some $n$; $e = \mathit{suc}^n\ 0$. Without canonicity terms in the language can get ``stuck'' -- meaning that they do not reduce to a canonical form. -Another approach is to use the \emph{setoid interpretation} of type theory -(\cite{hofmann-1995,huber-2016}). With this approach one works with -\nomen{extensional sets} $(X, \sim)$, that is a type $X \tp \MCU$ and an -equivalence relation $\sim \tp X \to X \to \MCU$ on that type. Under the setoid -interpretation the equivalence relation serve as a sort of ``local'' -propositional equality. This approach has other drawbacks; it does not satisfy +Another approach is to use the \emph{setoid interpretation} of type +theory (\cite{hofmann-1995,huber-2016}). With this approach one works +with +\nomenindex{extensional sets} $(X, \sim)$, that is a type $X \tp \MCU$ +and an equivalence relation $\sim\ \tp X \to X \to \MCU$ on that type. +Under the setoid interpretation the equivalence relation serve as a +sort of ``local'' propositional equality. Since the developer gets to +pick this relation it is not guaranteed to be a congruence relation +apriori. So this must be verified manually by the developer. +Furthermore, functions between different setoids must be shown to be +setoid homomorphism, that is; they preserve the relation. + +This approach has other drawbacks; it does not satisfy all propositional equalities of type theory (\TODO{Citation needed}), is cumbersome to work with in practice (\cite[p. 4]{huber-2016}) and makes equational proofs less reusable since equational proofs $a \sim_{X} b$ are @@ -163,14 +178,21 @@ inherently `local' to the extensional set $(X , \sim)$. \TODO{Talk a bit about terminology. Find a good place to stuff this little section.} -In the remainder of this paper I will use the term \nomen{Type} to describe -- +In the remainder of this paper I will use the term +\nomenindex{Type} to describe -- well, types. Thereby diverging from the notation in Agda where the keyword -\texttt{Set} refers to types. \nomen{Set} on the other hand shall refer to the +\texttt{Set} refers to types. +\nomenindex{Set} on the other hand shall refer to the homotopical notion of a set. I will also leave all universe levels implicit. -And I use the term \nomen{arrow} to refer to morphisms in a category, whereas -the terms morphism, map or function shall be reserved for talking about -type-theoretic functions; i.e. functions in Agda. +And I use the term +\nomenindex{arrow} to refer to morphisms in a category, +whereas the terms +\nomenindex{morphism}, +\nomenindex{map} or +\nomenindex{function} +shall be reserved for talking about type theoretic functions; i.e. +functions in Agda. $\defeq$ will be used for introducing definitions. $=$ will be used to for judgmental equality and $\equiv$ will be used for propositional equality. @@ -181,12 +203,16 @@ All this is summarized in the following table: \begin{tabular}{ c c c } Name & Agda & Notation \\ \hline -\nomen{Type} & \texttt{Set} & $\Type$ \\ -\nomen{Set} & \texttt{Σ Set IsSet} & $\Set$ \\ + +\varindex{Type} & \texttt{Set} & $\Type$ \\ + +\varindex{Set} & \texttt{Σ Set IsSet} & $\Set$ \\ Function, morphism, map & \texttt{A → B} & $A → B$ \\ Dependent- ditto & \texttt{(a : A) → B} & $∏_{a \tp A} B$ \\ -\nomen{Arrow} & \texttt{Arrow A B} & $\Arrow\ A\ B$ \\ -\nomen{Object} & \texttt{C.Object} & $̱ℂ.Object$ \\ + +\varindex{Arrow} & \texttt{Arrow A B} & $\Arrow\ A\ B$ \\ + +\varindex{Object} & \texttt{C.Object} & $̱ℂ.Object$ \\ Definition & \texttt{=} & $̱\defeq$ \\ Judgmental equality & \null & $̱=$ \\ Propositional equality & \null & $̱\equiv$ diff --git a/doc/macros.tex b/doc/macros.tex index 407eca0..0924882 100644 --- a/doc/macros.tex +++ b/doc/macros.tex @@ -17,7 +17,6 @@ \newcommand{\UU}{\ensuremath{\mathcal{U}}\xspace} \let\type\UU \newcommand{\MCU}{\UU} -\newcommand{\nomen}[1]{\emph{#1}} \newcommand{\todo}[1]{\textit{#1}} \newcommand{\comp}{\circ} \newcommand{\x}{\times} @@ -33,7 +32,9 @@ } \makeatother \newcommand{\var}[1]{\ensuremath{\mathit{#1}}} -\newcommand{\varindex}[1]{\ensuremath{\mathit{#1}}\index{#1}} +\newcommand{\varindex}[1]{\ensuremath{\var{#1}}\index{$\var{#1}$}} +\newcommand{\nomen}[2]{\emph{#1}\index{#2}} +\newcommand{\nomenindex}[1]{\nomen{#1}{#1}} \newcommand{\Hom}{\varindex{Hom}} \newcommand{\fmap}{\varindex{fmap}} @@ -93,3 +94,5 @@ \newcommand\funExt{\varindex{funExt}} \newcommand{\suc}[1]{\varindex{suc}\ #1} \newcommand{\trans}{\varindex{trans}} +\newcommand{\toKleisli}{\varindex{toKleisli}} +\newcommand{\toMonoidal}{\varindex{toMonoidal}} diff --git a/doc/packages.tex b/doc/packages.tex index c203951..20dddaa 100644 --- a/doc/packages.tex +++ b/doc/packages.tex @@ -113,3 +113,4 @@ } \makeatother +\usepackage{xspace} From 21363dbb78d424a5809302d8a78d2a3d728b80be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frederik=20Hangh=C3=B8j=20Iversen?= Date: Tue, 15 May 2018 16:28:04 +0200 Subject: [PATCH 05/33] Move opposite- and span- category to own modules --- doc/implementation.tex | 15 +- src/Cat.agda | 1 + src/Cat/Categories/CwF.agda | 1 + src/Cat/Categories/Fun.agda | 2 +- src/Cat/Categories/Opposite.agda | 96 ++++++++ src/Cat/Categories/Sets.agda | 4 +- src/Cat/Categories/Span.agda | 173 ++++++++++++++ src/Cat/Category.agda | 92 -------- src/Cat/Category/Product.agda | 377 +++++++++---------------------- src/Cat/Category/Yoneda.agda | 4 +- 10 files changed, 389 insertions(+), 376 deletions(-) create mode 100644 src/Cat/Categories/Opposite.agda create mode 100644 src/Cat/Categories/Span.agda diff --git a/doc/implementation.tex b/doc/implementation.tex index d94f033..75f2df7 100644 --- a/doc/implementation.tex +++ b/doc/implementation.tex @@ -10,19 +10,20 @@ Name & Link \\ \hline Categories & \sourcelink{Cat.Category} \\ Functors & \sourcelink{Cat.Category.Functor} \\ -Products & \sourcelink{Cat.Category.Products} \\ -Exponentials & \sourcelink{Cat.Category.Exponentials} \\ +Products & \sourcelink{Cat.Category.Product} \\ +Exponentials & \sourcelink{Cat.Category.Exponential} \\ Cartesian closed categories & \sourcelink{Cat.Category.CartesianClosed} \\ Natural transformations & \sourcelink{Cat.Category.NaturalTransformation} \\ Yoneda embedding & \sourcelink{Cat.Category.Yoneda} \\ -Monads & \sourcelink{Cat.Category.Monads} \\ +Monads & \sourcelink{Cat.Category.Monad} \\ +Kleisli Monads & \sourcelink{Cat.Category.Monad.Kleisli} \\ +Monoidal Monads & \sourcelink{Cat.Category.Monad.Monoidal} \\ +Voevodsky's construction & \sourcelink{Cat.Category.Monad.Voevodsky} \\ %% Categories & \null \\ %% -Opposite category & -\href{\sourcebasepath Cat.Category.html#22744}{\texttt{Cat.Category.Opposite}} \\ +Opposite category & \sourcelink{Cat.Categories.Opposite} \\ Category of sets & \sourcelink{Cat.Categories.Sets} \\ -Span category & -\href{\sourcebasepath Cat.Category.Product.html#2919}{\texttt{Cat.Category.Product.Span}} \\ +Span category & \sourcelink{Cat.Categories.Span} \\ %% \end{tabular} \end{center} diff --git a/src/Cat.agda b/src/Cat.agda index fca9c99..a2d73e8 100644 --- a/src/Cat.agda +++ b/src/Cat.agda @@ -14,6 +14,7 @@ open import Cat.Category.Monad.Monoidal open import Cat.Category.Monad.Kleisli open import Cat.Category.Monad.Voevodsky +open import Cat.Categories.Opposite open import Cat.Categories.Sets open import Cat.Categories.Cat open import Cat.Categories.Rel diff --git a/src/Cat/Categories/CwF.agda b/src/Cat/Categories/CwF.agda index 1a491ec..9c1fc6d 100644 --- a/src/Cat/Categories/CwF.agda +++ b/src/Cat/Categories/CwF.agda @@ -5,6 +5,7 @@ open import Cat.Prelude open import Cat.Category open import Cat.Category.Functor open import Cat.Categories.Fam +open import Cat.Categories.Opposite module _ {ℓa ℓb : Level} where record CwF : Set (lsuc (ℓa ⊔ ℓb)) where diff --git a/src/Cat/Categories/Fun.agda b/src/Cat/Categories/Fun.agda index eb861e7..bcfb508 100644 --- a/src/Cat/Categories/Fun.agda +++ b/src/Cat/Categories/Fun.agda @@ -3,11 +3,11 @@ module Cat.Categories.Fun where open import Cat.Prelude open import Cat.Equivalence - open import Cat.Category open import Cat.Category.Functor import Cat.Category.NaturalTransformation as NaturalTransformation +open import Cat.Categories.Opposite module Fun {ℓc ℓc' ℓd ℓd' : Level} (ℂ : Category ℓc ℓc') (𝔻 : Category ℓd ℓd') where open NaturalTransformation ℂ 𝔻 public hiding (module Properties) diff --git a/src/Cat/Categories/Opposite.agda b/src/Cat/Categories/Opposite.agda new file mode 100644 index 0000000..ef2fa33 --- /dev/null +++ b/src/Cat/Categories/Opposite.agda @@ -0,0 +1,96 @@ +{-# OPTIONS --cubical #-} +module Cat.Categories.Opposite where + +open import Cat.Prelude +open import Cat.Equivalence +open import Cat.Category + +-- | The opposite category +-- +-- The opposite category is the category where the direction of the arrows are +-- flipped. +module _ {ℓa ℓb : Level} where + module _ (ℂ : Category ℓa ℓb) where + private + module _ where + module ℂ = Category ℂ + opRaw : RawCategory ℓa ℓb + RawCategory.Object opRaw = ℂ.Object + RawCategory.Arrow opRaw = flip ℂ.Arrow + RawCategory.identity opRaw = ℂ.identity + RawCategory._<<<_ opRaw = ℂ._>>>_ + + open RawCategory opRaw + + isPreCategory : IsPreCategory opRaw + IsPreCategory.isAssociative isPreCategory = sym ℂ.isAssociative + IsPreCategory.isIdentity isPreCategory = swap ℂ.isIdentity + IsPreCategory.arrowsAreSets isPreCategory = ℂ.arrowsAreSets + + open IsPreCategory isPreCategory + + module _ {A B : ℂ.Object} where + open Σ (toIso _ _ (ℂ.univalent {A} {B})) + renaming (fst to idToIso* ; snd to inv*) + open AreInverses {f = ℂ.idToIso A B} {idToIso*} inv* + + shuffle : A ≊ B → A ℂ.≊ B + shuffle (f , g , inv) = g , f , inv + + shuffle~ : A ℂ.≊ B → A ≊ B + shuffle~ (f , g , inv) = g , f , inv + + lem : (p : A ≡ B) → idToIso A B p ≡ shuffle~ (ℂ.idToIso A B p) + lem p = isoEq refl + + isoToId* : A ≊ B → A ≡ B + isoToId* = idToIso* ∘ shuffle + + inv : AreInverses (idToIso A B) isoToId* + inv = + ( funExt (λ x → begin + (isoToId* ∘ idToIso A B) x + ≡⟨⟩ + (idToIso* ∘ shuffle ∘ idToIso A B) x + ≡⟨ cong (λ φ → φ x) (cong (λ φ → idToIso* ∘ shuffle ∘ φ) (funExt lem)) ⟩ + (idToIso* ∘ shuffle ∘ shuffle~ ∘ ℂ.idToIso A B) x + ≡⟨⟩ + (idToIso* ∘ ℂ.idToIso A B) x + ≡⟨ (λ i → verso-recto i x) ⟩ + x ∎) + , funExt (λ x → begin + (idToIso A B ∘ idToIso* ∘ shuffle) x + ≡⟨ cong (λ φ → φ x) (cong (λ φ → φ ∘ idToIso* ∘ shuffle) (funExt lem)) ⟩ + (shuffle~ ∘ ℂ.idToIso A B ∘ idToIso* ∘ shuffle) x + ≡⟨ cong (λ φ → φ x) (cong (λ φ → shuffle~ ∘ φ ∘ shuffle) recto-verso) ⟩ + (shuffle~ ∘ shuffle) x + ≡⟨⟩ + x ∎) + ) + + isCategory : IsCategory opRaw + IsCategory.isPreCategory isCategory = isPreCategory + IsCategory.univalent isCategory + = univalenceFromIsomorphism (isoToId* , inv) + + 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.identity (rawInv _) = identity + RawCategory._<<<_ (rawInv _) = _<<<_ + + oppositeIsInvolution : opposite (opposite ℂ) ≡ ℂ + oppositeIsInvolution = Category≡ rawInv diff --git a/src/Cat/Categories/Sets.agda b/src/Cat/Categories/Sets.agda index e707b55..e25f148 100644 --- a/src/Cat/Categories/Sets.agda +++ b/src/Cat/Categories/Sets.agda @@ -3,11 +3,11 @@ module Cat.Categories.Sets where open import Cat.Prelude as P - +open import Cat.Equivalence open import Cat.Category open import Cat.Category.Functor open import Cat.Category.Product -open import Cat.Equivalence +open import Cat.Categories.Opposite _⊙_ : {ℓa ℓb ℓc : Level} {A : Set ℓa} {B : Set ℓb} {C : Set ℓc} → (A ≃ B) → (B ≃ C) → A ≃ C eqA ⊙ eqB = Equivalence.compose eqA eqB diff --git a/src/Cat/Categories/Span.agda b/src/Cat/Categories/Span.agda new file mode 100644 index 0000000..3573266 --- /dev/null +++ b/src/Cat/Categories/Span.agda @@ -0,0 +1,173 @@ +{-# OPTIONS --cubical --caching #-} +module Cat.Categories.Span where + +open import Cat.Prelude as P hiding (_×_ ; fst ; snd) +open import Cat.Equivalence +open import Cat.Category + +module _ {ℓa ℓb : Level} (ℂ : Category ℓa ℓb) + (let module ℂ = Category ℂ) (𝒜 ℬ : ℂ.Object) where + + open P + + private + module _ where + raw : RawCategory _ _ + raw = record + { Object = Σ[ X ∈ ℂ.Object ] ℂ.Arrow X 𝒜 × ℂ.Arrow X ℬ + ; Arrow = λ{ (A , a0 , a1) (B , b0 , b1) + → Σ[ f ∈ ℂ.Arrow A B ] + ℂ [ b0 ∘ f ] ≡ a0 + × ℂ [ b1 ∘ f ] ≡ a1 + } + ; identity = λ{ {X , f , g} → ℂ.identity {X} , ℂ.rightIdentity , ℂ.rightIdentity} + ; _<<<_ = λ { {_ , a0 , a1} {_ , b0 , b1} {_ , c0 , c1} (f , f0 , f1) (g , g0 , g1) + → (f ℂ.<<< g) + , (begin + ℂ [ c0 ∘ ℂ [ f ∘ g ] ] ≡⟨ ℂ.isAssociative ⟩ + ℂ [ ℂ [ c0 ∘ f ] ∘ g ] ≡⟨ cong (λ φ → ℂ [ φ ∘ g ]) f0 ⟩ + ℂ [ b0 ∘ g ] ≡⟨ g0 ⟩ + a0 ∎ + ) + , (begin + ℂ [ c1 ∘ ℂ [ f ∘ g ] ] ≡⟨ ℂ.isAssociative ⟩ + ℂ [ ℂ [ c1 ∘ f ] ∘ g ] ≡⟨ cong (λ φ → ℂ [ φ ∘ g ]) f1 ⟩ + ℂ [ b1 ∘ g ] ≡⟨ g1 ⟩ + a1 ∎ + ) + } + } + + module _ where + open RawCategory raw + + propEqs : ∀ {X' : Object}{Y' : Object} (let X , xa , xb = X') (let Y , ya , yb = Y') + → (xy : ℂ.Arrow X Y) → isProp (ℂ [ ya ∘ xy ] ≡ xa × ℂ [ yb ∘ xy ] ≡ xb) + propEqs xs = propSig (ℂ.arrowsAreSets _ _) (\ _ → ℂ.arrowsAreSets _ _) + + arrowEq : {X Y : Object} {f g : Arrow X Y} → fst f ≡ fst g → f ≡ g + arrowEq {X} {Y} {f} {g} p = λ i → p i , lemPropF propEqs p {snd f} {snd g} i + + isAssociative : IsAssociative + isAssociative {f = f , f0 , f1} {g , g0 , g1} {h , h0 , h1} = arrowEq ℂ.isAssociative + + isIdentity : IsIdentity identity + isIdentity {AA@(A , a0 , a1)} {BB@(B , b0 , b1)} {f , f0 , f1} = arrowEq ℂ.leftIdentity , arrowEq ℂ.rightIdentity + + arrowsAreSets : ArrowsAreSets + arrowsAreSets {X , x0 , x1} {Y , y0 , y1} + = sigPresSet ℂ.arrowsAreSets λ a → propSet (propEqs _) + + isPreCat : IsPreCategory raw + IsPreCategory.isAssociative isPreCat = isAssociative + IsPreCategory.isIdentity isPreCat = isIdentity + IsPreCategory.arrowsAreSets isPreCat = arrowsAreSets + + open IsPreCategory isPreCat + + module _ {𝕏 𝕐 : Object} where + open Σ 𝕏 renaming (fst to X ; snd to x) + open Σ x renaming (fst to xa ; snd to xb) + open Σ 𝕐 renaming (fst to Y ; snd to y) + open Σ y renaming (fst to ya ; snd to yb) + open import Cat.Equivalence using (composeIso) renaming (_≅_ to _≅_) + step0 + : ((X , xa , xb) ≡ (Y , ya , yb)) + ≅ (Σ[ p ∈ (X ≡ Y) ] (PathP (λ i → ℂ.Arrow (p i) 𝒜) xa ya) × (PathP (λ i → ℂ.Arrow (p i) ℬ) xb yb)) + step0 + = (λ p → cong fst p , cong-d (fst ∘ snd) p , cong-d (snd ∘ snd) p) + -- , (λ x → λ i → fst x i , (fst (snd x) i) , (snd (snd x) i)) + , (λ{ (p , q , r) → Σ≡ p λ i → q i , r i}) + , funExt (λ{ p → refl}) + , funExt (λ{ (p , q , r) → refl}) + + step1 + : (Σ[ p ∈ (X ≡ Y) ] (PathP (λ i → ℂ.Arrow (p i) 𝒜) xa ya) × (PathP (λ i → ℂ.Arrow (p i) ℬ) xb yb)) + ≅ Σ (X ℂ.≊ Y) (λ iso + → let p = ℂ.isoToId iso + in + ( PathP (λ i → ℂ.Arrow (p i) 𝒜) xa ya) + × PathP (λ i → ℂ.Arrow (p i) ℬ) xb yb + ) + step1 + = symIso + (isoSigFst + {A = (X ℂ.≊ Y)} + {B = (X ≡ Y)} + (ℂ.groupoidObject _ _) + {Q = \ p → (PathP (λ i → ℂ.Arrow (p i) 𝒜) xa ya) × (PathP (λ i → ℂ.Arrow (p i) ℬ) xb yb)} + ℂ.isoToId + (symIso (_ , ℂ.asTypeIso {X} {Y}) .snd) + ) + + step2 + : Σ (X ℂ.≊ Y) (λ iso + → let p = ℂ.isoToId iso + in + ( PathP (λ i → ℂ.Arrow (p i) 𝒜) xa ya) + × PathP (λ i → ℂ.Arrow (p i) ℬ) xb yb + ) + ≅ ((X , xa , xb) ≊ (Y , ya , yb)) + step2 + = ( λ{ (iso@(f , f~ , inv-f) , p , q) + → ( f , sym (ℂ.domain-twist-sym iso p) , sym (ℂ.domain-twist-sym iso q)) + , ( f~ , sym (ℂ.domain-twist iso p) , sym (ℂ.domain-twist iso q)) + , arrowEq (fst inv-f) + , arrowEq (snd inv-f) + } + ) + , (λ{ (f , f~ , inv-f , inv-f~) → + let + iso : X ℂ.≊ Y + iso = fst f , fst f~ , cong fst inv-f , cong fst inv-f~ + p : X ≡ Y + p = ℂ.isoToId iso + pA : ℂ.Arrow X 𝒜 ≡ ℂ.Arrow Y 𝒜 + pA = cong (λ x → ℂ.Arrow x 𝒜) p + pB : ℂ.Arrow X ℬ ≡ ℂ.Arrow Y ℬ + pB = cong (λ x → ℂ.Arrow x ℬ) p + k0 = begin + coe pB xb ≡⟨ ℂ.coe-dom iso ⟩ + xb ℂ.<<< fst f~ ≡⟨ snd (snd f~) ⟩ + yb ∎ + k1 = begin + coe pA xa ≡⟨ ℂ.coe-dom iso ⟩ + xa ℂ.<<< fst f~ ≡⟨ fst (snd f~) ⟩ + ya ∎ + in iso , coe-lem-inv k1 , coe-lem-inv k0}) + , funExt (λ x → lemSig + (λ x → propSig prop0 (λ _ → prop1)) + _ _ + (Σ≡ refl (ℂ.propIsomorphism _ _ _))) + , funExt (λ{ (f , _) → lemSig propIsomorphism _ _ (Σ≡ refl (propEqs _ _ _))}) + where + prop0 : ∀ {x} → isProp (PathP (λ i → ℂ.Arrow (ℂ.isoToId x i) 𝒜) xa ya) + prop0 {x} = pathJ (λ y p → ∀ x → isProp (PathP (λ i → ℂ.Arrow (p i) 𝒜) xa x)) (λ x → ℂ.arrowsAreSets _ _) Y (ℂ.isoToId x) ya + prop1 : ∀ {x} → isProp (PathP (λ i → ℂ.Arrow (ℂ.isoToId x i) ℬ) xb yb) + prop1 {x} = pathJ (λ y p → ∀ x → isProp (PathP (λ i → ℂ.Arrow (p i) ℬ) xb x)) (λ x → ℂ.arrowsAreSets _ _) Y (ℂ.isoToId x) yb + -- One thing to watch out for here is that the isomorphisms going forwards + -- must compose to give idToIso + iso + : ((X , xa , xb) ≡ (Y , ya , yb)) + ≅ ((X , xa , xb) ≊ (Y , ya , yb)) + iso = step0 ⊙ step1 ⊙ step2 + where + infixl 5 _⊙_ + _⊙_ = composeIso + equiv1 + : ((X , xa , xb) ≡ (Y , ya , yb)) + ≃ ((X , xa , xb) ≊ (Y , ya , yb)) + equiv1 = _ , fromIso _ _ (snd iso) + + univalent : Univalent + univalent = univalenceFrom≃ equiv1 + + isCat : IsCategory raw + IsCategory.isPreCategory isCat = isPreCat + IsCategory.univalent isCat = univalent + + span : Category _ _ + span = record + { raw = raw + ; isCategory = isCat + } diff --git a/src/Cat/Category.agda b/src/Cat/Category.agda index 274f94e..139fba9 100644 --- a/src/Cat/Category.agda +++ b/src/Cat/Category.agda @@ -631,95 +631,3 @@ module _ {ℓa ℓb : Level} (ℂ : Category ℓa ℓb) where _[_∘_] : {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 _ where - module ℂ = Category ℂ - opRaw : RawCategory ℓa ℓb - RawCategory.Object opRaw = ℂ.Object - RawCategory.Arrow opRaw = flip ℂ.Arrow - RawCategory.identity opRaw = ℂ.identity - RawCategory._<<<_ opRaw = ℂ._>>>_ - - open RawCategory opRaw - - isPreCategory : IsPreCategory opRaw - IsPreCategory.isAssociative isPreCategory = sym ℂ.isAssociative - IsPreCategory.isIdentity isPreCategory = swap ℂ.isIdentity - IsPreCategory.arrowsAreSets isPreCategory = ℂ.arrowsAreSets - - open IsPreCategory isPreCategory - - module _ {A B : ℂ.Object} where - open Σ (toIso _ _ (ℂ.univalent {A} {B})) - renaming (fst to idToIso* ; snd to inv*) - open AreInverses {f = ℂ.idToIso A B} {idToIso*} inv* - - shuffle : A ≊ B → A ℂ.≊ B - shuffle (f , g , inv) = g , f , inv - - shuffle~ : A ℂ.≊ B → A ≊ B - shuffle~ (f , g , inv) = g , f , inv - - lem : (p : A ≡ B) → idToIso A B p ≡ shuffle~ (ℂ.idToIso A B p) - lem p = isoEq refl - - isoToId* : A ≊ B → A ≡ B - isoToId* = idToIso* ∘ shuffle - - inv : AreInverses (idToIso A B) isoToId* - inv = - ( funExt (λ x → begin - (isoToId* ∘ idToIso A B) x - ≡⟨⟩ - (idToIso* ∘ shuffle ∘ idToIso A B) x - ≡⟨ cong (λ φ → φ x) (cong (λ φ → idToIso* ∘ shuffle ∘ φ) (funExt lem)) ⟩ - (idToIso* ∘ shuffle ∘ shuffle~ ∘ ℂ.idToIso A B) x - ≡⟨⟩ - (idToIso* ∘ ℂ.idToIso A B) x - ≡⟨ (λ i → verso-recto i x) ⟩ - x ∎) - , funExt (λ x → begin - (idToIso A B ∘ idToIso* ∘ shuffle) x - ≡⟨ cong (λ φ → φ x) (cong (λ φ → φ ∘ idToIso* ∘ shuffle) (funExt lem)) ⟩ - (shuffle~ ∘ ℂ.idToIso A B ∘ idToIso* ∘ shuffle) x - ≡⟨ cong (λ φ → φ x) (cong (λ φ → shuffle~ ∘ φ ∘ shuffle) recto-verso) ⟩ - (shuffle~ ∘ shuffle) x - ≡⟨⟩ - x ∎) - ) - - isCategory : IsCategory opRaw - IsCategory.isPreCategory isCategory = isPreCategory - IsCategory.univalent isCategory - = univalenceFromIsomorphism (isoToId* , inv) - - 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.identity (rawInv _) = identity - RawCategory._<<<_ (rawInv _) = _<<<_ - - oppositeIsInvolution : opposite (opposite ℂ) ≡ ℂ - oppositeIsInvolution = Category≡ rawInv - -open Opposite public diff --git a/src/Cat/Category/Product.agda b/src/Cat/Category/Product.agda index 4856668..41d10e2 100644 --- a/src/Cat/Category/Product.agda +++ b/src/Cat/Category/Product.agda @@ -55,286 +55,122 @@ module _ {ℓa ℓb : Level} (ℂ : Category ℓa ℓb) where × ℂ [ g ∘ snd ] ] -module _ {ℓa ℓb : Level} {ℂ : Category ℓa ℓb} {A B : Category.Object ℂ} where +module _ {ℓa ℓb : Level} {ℂ : Category ℓa ℓb} + (let module ℂ = Category ℂ) {𝒜 ℬ : ℂ.Object} where private - open Category ℂ - module _ (raw : RawProduct ℂ A B) where - module _ (x y : IsProduct ℂ A B raw) where - private - module x = IsProduct x - module y = IsProduct y + module _ (raw : RawProduct ℂ 𝒜 ℬ) where + private + open Category ℂ hiding (raw) + module _ (x y : IsProduct ℂ 𝒜 ℬ raw) where + private + module x = IsProduct x + module y = IsProduct y - module _ {X : Object} (f : ℂ [ X , A ]) (g : ℂ [ X , B ]) where - module _ (f×g : Arrow X y.object) where - help : isProp (∀{y} → (ℂ [ y.fst ∘ y ] ≡ f) P.× (ℂ [ y.snd ∘ y ] ≡ g) → f×g ≡ y) - help = propPiImpl (λ _ → propPi (λ _ → arrowsAreSets _ _)) + module _ {X : Object} (f : ℂ [ X , 𝒜 ]) (g : ℂ [ X , ℬ ]) where + module _ (f×g : Arrow X y.object) where + help : isProp (∀{y} → (ℂ [ y.fst ∘ y ] ≡ f) P.× (ℂ [ y.snd ∘ y ] ≡ g) → f×g ≡ y) + help = propPiImpl (λ _ → propPi (λ _ → arrowsAreSets _ _)) - res = ∃-unique (x.ump f g) (y.ump f g) + res = ∃-unique (x.ump f g) (y.ump f g) - prodAux : x.ump f g ≡ y.ump f g - prodAux = lemSig ((λ f×g → propSig (propSig (arrowsAreSets _ _) λ _ → arrowsAreSets _ _) (λ _ → help f×g))) _ _ res + prodAux : x.ump f g ≡ y.ump f g + prodAux = lemSig ((λ f×g → propSig (propSig (arrowsAreSets _ _) λ _ → arrowsAreSets _ _) (λ _ → help f×g))) _ _ res - propIsProduct' : x ≡ y - propIsProduct' i = record { ump = λ f g → prodAux f g i } + propIsProduct' : x ≡ y + propIsProduct' i = record { ump = λ f g → prodAux f g i } - propIsProduct : isProp (IsProduct ℂ A B raw) + propIsProduct : isProp (IsProduct ℂ 𝒜 ℬ raw) propIsProduct = propIsProduct' - Product≡ : {x y : Product ℂ A B} → (Product.raw x ≡ Product.raw y) → x ≡ y - Product≡ {x} {y} p i = record { raw = p i ; isProduct = q i } - where - q : (λ i → IsProduct ℂ A B (p i)) [ Product.isProduct x ≡ Product.isProduct y ] - q = lemPropF propIsProduct p + Product≡ : {x y : Product ℂ 𝒜 ℬ} → (Product.raw x ≡ Product.raw y) → x ≡ y + Product≡ {x} {y} p i = record { raw = p i ; isProduct = q i } + where + q : (λ i → IsProduct ℂ 𝒜 ℬ (p i)) [ Product.isProduct x ≡ Product.isProduct y ] + q = lemPropF propIsProduct p -module Try0 {ℓa ℓb : Level} {ℂ : Category ℓa ℓb} - (let module ℂ = Category ℂ) {𝒜 ℬ : ℂ.Object} where + open P + open import Cat.Categories.Span - open P + open Category (span ℂ 𝒜 ℬ) - module _ where - raw : RawCategory _ _ - raw = record - { Object = Σ[ X ∈ ℂ.Object ] ℂ.Arrow X 𝒜 × ℂ.Arrow X ℬ - ; Arrow = λ{ (A , a0 , a1) (B , b0 , b1) - → Σ[ f ∈ ℂ.Arrow A B ] - ℂ [ b0 ∘ f ] ≡ a0 - × ℂ [ b1 ∘ f ] ≡ a1 - } - ; identity = λ{ {X , f , g} → ℂ.identity {X} , ℂ.rightIdentity , ℂ.rightIdentity} - ; _<<<_ = λ { {_ , a0 , a1} {_ , b0 , b1} {_ , c0 , c1} (f , f0 , f1) (g , g0 , g1) - → (f ℂ.<<< g) - , (begin - ℂ [ c0 ∘ ℂ [ f ∘ g ] ] ≡⟨ ℂ.isAssociative ⟩ - ℂ [ ℂ [ c0 ∘ f ] ∘ g ] ≡⟨ cong (λ φ → ℂ [ φ ∘ g ]) f0 ⟩ - ℂ [ b0 ∘ g ] ≡⟨ g0 ⟩ - a0 ∎ - ) - , (begin - ℂ [ c1 ∘ ℂ [ f ∘ g ] ] ≡⟨ ℂ.isAssociative ⟩ - ℂ [ ℂ [ c1 ∘ f ] ∘ g ] ≡⟨ cong (λ φ → ℂ [ φ ∘ g ]) f1 ⟩ - ℂ [ b1 ∘ g ] ≡⟨ g1 ⟩ - a1 ∎ - ) - } - } - - module _ where - open RawCategory raw - - propEqs : ∀ {X' : Object}{Y' : Object} (let X , xa , xb = X') (let Y , ya , yb = Y') - → (xy : ℂ.Arrow X Y) → isProp (ℂ [ ya ∘ xy ] ≡ xa × ℂ [ yb ∘ xy ] ≡ xb) - propEqs xs = propSig (ℂ.arrowsAreSets _ _) (\ _ → ℂ.arrowsAreSets _ _) - - arrowEq : {X Y : Object} {f g : Arrow X Y} → fst f ≡ fst g → f ≡ g - arrowEq {X} {Y} {f} {g} p = λ i → p i , lemPropF propEqs p {snd f} {snd g} i - - private - isAssociative : IsAssociative - isAssociative {f = f , f0 , f1} {g , g0 , g1} {h , h0 , h1} = arrowEq ℂ.isAssociative - - isIdentity : IsIdentity identity - isIdentity {AA@(A , a0 , a1)} {BB@(B , b0 , b1)} {f , f0 , f1} = arrowEq ℂ.leftIdentity , arrowEq ℂ.rightIdentity - - arrowsAreSets : ArrowsAreSets - arrowsAreSets {X , x0 , x1} {Y , y0 , y1} - = sigPresSet ℂ.arrowsAreSets λ a → propSet (propEqs _) - - isPreCat : IsPreCategory raw - IsPreCategory.isAssociative isPreCat = isAssociative - IsPreCategory.isIdentity isPreCat = isIdentity - IsPreCategory.arrowsAreSets isPreCat = arrowsAreSets - - open IsPreCategory isPreCat - - module _ {𝕏 𝕐 : Object} where - open Σ 𝕏 renaming (fst to X ; snd to x) - open Σ x renaming (fst to xa ; snd to xb) - open Σ 𝕐 renaming (fst to Y ; snd to y) - open Σ y renaming (fst to ya ; snd to yb) - open import Cat.Equivalence using (composeIso) renaming (_≅_ to _≅_) - step0 - : ((X , xa , xb) ≡ (Y , ya , yb)) - ≅ (Σ[ p ∈ (X ≡ Y) ] (PathP (λ i → ℂ.Arrow (p i) 𝒜) xa ya) × (PathP (λ i → ℂ.Arrow (p i) ℬ) xb yb)) - step0 - = (λ p → cong fst p , cong-d (fst ∘ snd) p , cong-d (snd ∘ snd) p) - -- , (λ x → λ i → fst x i , (fst (snd x) i) , (snd (snd x) i)) - , (λ{ (p , q , r) → Σ≡ p λ i → q i , r i}) - , funExt (λ{ p → refl}) - , funExt (λ{ (p , q , r) → refl}) - - step1 - : (Σ[ p ∈ (X ≡ Y) ] (PathP (λ i → ℂ.Arrow (p i) 𝒜) xa ya) × (PathP (λ i → ℂ.Arrow (p i) ℬ) xb yb)) - ≅ Σ (X ℂ.≊ Y) (λ iso - → let p = ℂ.isoToId iso - in - ( PathP (λ i → ℂ.Arrow (p i) 𝒜) xa ya) - × PathP (λ i → ℂ.Arrow (p i) ℬ) xb yb - ) - step1 - = symIso - (isoSigFst - {A = (X ℂ.≊ Y)} - {B = (X ≡ Y)} - (ℂ.groupoidObject _ _) - {Q = \ p → (PathP (λ i → ℂ.Arrow (p i) 𝒜) xa ya) × (PathP (λ i → ℂ.Arrow (p i) ℬ) xb yb)} - ℂ.isoToId - (symIso (_ , ℂ.asTypeIso {X} {Y}) .snd) - ) - - step2 - : Σ (X ℂ.≊ Y) (λ iso - → let p = ℂ.isoToId iso - in - ( PathP (λ i → ℂ.Arrow (p i) 𝒜) xa ya) - × PathP (λ i → ℂ.Arrow (p i) ℬ) xb yb - ) - ≅ ((X , xa , xb) ≊ (Y , ya , yb)) - step2 - = ( λ{ (iso@(f , f~ , inv-f) , p , q) - → ( f , sym (ℂ.domain-twist-sym iso p) , sym (ℂ.domain-twist-sym iso q)) - , ( f~ , sym (ℂ.domain-twist iso p) , sym (ℂ.domain-twist iso q)) - , arrowEq (fst inv-f) - , arrowEq (snd inv-f) - } - ) - , (λ{ (f , f~ , inv-f , inv-f~) → - let - iso : X ℂ.≊ Y - iso = fst f , fst f~ , cong fst inv-f , cong fst inv-f~ - p : X ≡ Y - p = ℂ.isoToId iso - pA : ℂ.Arrow X 𝒜 ≡ ℂ.Arrow Y 𝒜 - pA = cong (λ x → ℂ.Arrow x 𝒜) p - pB : ℂ.Arrow X ℬ ≡ ℂ.Arrow Y ℬ - pB = cong (λ x → ℂ.Arrow x ℬ) p - k0 = begin - coe pB xb ≡⟨ ℂ.coe-dom iso ⟩ - xb ℂ.<<< fst f~ ≡⟨ snd (snd f~) ⟩ - yb ∎ - k1 = begin - coe pA xa ≡⟨ ℂ.coe-dom iso ⟩ - xa ℂ.<<< fst f~ ≡⟨ fst (snd f~) ⟩ - ya ∎ - in iso , coe-lem-inv k1 , coe-lem-inv k0}) - , funExt (λ x → lemSig - (λ x → propSig prop0 (λ _ → prop1)) - _ _ - (Σ≡ refl (ℂ.propIsomorphism _ _ _))) - , funExt (λ{ (f , _) → lemSig propIsomorphism _ _ (Σ≡ refl (propEqs _ _ _))}) - where - prop0 : ∀ {x} → isProp (PathP (λ i → ℂ.Arrow (ℂ.isoToId x i) 𝒜) xa ya) - prop0 {x} = pathJ (λ y p → ∀ x → isProp (PathP (λ i → ℂ.Arrow (p i) 𝒜) xa x)) (λ x → ℂ.arrowsAreSets _ _) Y (ℂ.isoToId x) ya - prop1 : ∀ {x} → isProp (PathP (λ i → ℂ.Arrow (ℂ.isoToId x i) ℬ) xb yb) - prop1 {x} = pathJ (λ y p → ∀ x → isProp (PathP (λ i → ℂ.Arrow (p i) ℬ) xb x)) (λ x → ℂ.arrowsAreSets _ _) Y (ℂ.isoToId x) yb - -- One thing to watch out for here is that the isomorphisms going forwards - -- must compose to give idToIso - iso - : ((X , xa , xb) ≡ (Y , ya , yb)) - ≅ ((X , xa , xb) ≊ (Y , ya , yb)) - iso = step0 ⊙ step1 ⊙ step2 + lemma : Terminal ≃ Product ℂ 𝒜 ℬ + lemma = fromIsomorphism Terminal (Product ℂ 𝒜 ℬ) (f , g , inv) + where + f : Terminal → Product ℂ 𝒜 ℬ + f ((X , x0 , x1) , uniq) = p where - infixl 5 _⊙_ - _⊙_ = composeIso - equiv1 - : ((X , xa , xb) ≡ (Y , ya , yb)) - ≃ ((X , xa , xb) ≊ (Y , ya , yb)) - equiv1 = _ , fromIso _ _ (snd iso) - - univalent : Univalent - univalent = univalenceFrom≃ equiv1 - - isCat : IsCategory raw - IsCategory.isPreCategory isCat = isPreCat - IsCategory.univalent isCat = univalent - - cat : Category _ _ - cat = record - { raw = raw - ; isCategory = isCat - } - - open Category cat - - lemma : Terminal ≃ Product ℂ 𝒜 ℬ - lemma = fromIsomorphism Terminal (Product ℂ 𝒜 ℬ) (f , g , inv) - -- C-x 8 RET MATHEMATICAL BOLD SCRIPT CAPITAL A - -- 𝒜 - where - f : Terminal → Product ℂ 𝒜 ℬ - f ((X , x0 , x1) , uniq) = p - where - rawP : RawProduct ℂ 𝒜 ℬ - rawP = record - { object = X - ; fst = x0 - ; snd = x1 - } - -- open RawProduct rawP renaming (fst to x0 ; snd to x1) - module _ {Y : ℂ.Object} (p0 : ℂ [ Y , 𝒜 ]) (p1 : ℂ [ Y , ℬ ]) where - uy : isContr (Arrow (Y , p0 , p1) (X , x0 , x1)) - uy = uniq {Y , p0 , p1} - open Σ uy renaming (fst to Y→X ; snd to contractible) - open Σ Y→X renaming (fst to p0×p1 ; snd to cond) - ump : ∃![ f×g ] (ℂ [ x0 ∘ f×g ] ≡ p0 P.× ℂ [ x1 ∘ f×g ] ≡ p1) - ump = p0×p1 , cond , λ {f} cond-f → cong fst (contractible (f , cond-f)) - isP : IsProduct ℂ 𝒜 ℬ rawP - isP = record { ump = ump } - p : Product ℂ 𝒜 ℬ - p = record - { raw = rawP - ; isProduct = isP - } - g : Product ℂ 𝒜 ℬ → Terminal - g p = 𝒳 , t - where - open Product p renaming (object to X ; fst to x₀ ; snd to x₁) using () - module p = Product p - module isp = IsProduct p.isProduct - 𝒳 : Object - 𝒳 = X , x₀ , x₁ - module _ {𝒴 : Object} where - open Σ 𝒴 renaming (fst to Y) - open Σ (snd 𝒴) renaming (fst to y₀ ; snd to y₁) - ump = p.ump y₀ y₁ - open Σ ump renaming (fst to f') - open Σ (snd ump) renaming (fst to f'-cond) - 𝒻 : Arrow 𝒴 𝒳 - 𝒻 = f' , f'-cond - contractible : (f : Arrow 𝒴 𝒳) → 𝒻 ≡ f - contractible ff@(f , f-cond) = res - where - k : f' ≡ f - k = snd (snd ump) f-cond - prp : (a : ℂ.Arrow Y X) → isProp - ( (ℂ [ x₀ ∘ a ] ≡ y₀) - × (ℂ [ x₁ ∘ a ] ≡ y₁) - ) - prp f f0 f1 = Σ≡ - (ℂ.arrowsAreSets _ _ (fst f0) (fst f1)) - (ℂ.arrowsAreSets _ _ (snd f0) (snd f1)) - h : - ( λ i - → ℂ [ x₀ ∘ k i ] ≡ y₀ - × ℂ [ x₁ ∘ k i ] ≡ y₁ - ) [ f'-cond ≡ f-cond ] - h = lemPropF prp k - res : (f' , f'-cond) ≡ (f , f-cond) - res = Σ≡ k h - t : IsTerminal 𝒳 - t {𝒴} = 𝒻 , contractible - ve-re : ∀ x → g (f x) ≡ x - ve-re x = Propositionality.propTerminal _ _ - re-ve : ∀ p → f (g p) ≡ p - re-ve p = Product≡ e - where - module p = Product p - -- RawProduct does not have eta-equality. - e : Product.raw (f (g p)) ≡ Product.raw p - RawProduct.object (e i) = p.object - RawProduct.fst (e i) = p.fst - RawProduct.snd (e i) = p.snd - inv : AreInverses f g - inv = funExt ve-re , funExt re-ve + rawP : RawProduct ℂ 𝒜 ℬ + rawP = record + { object = X + ; fst = x0 + ; snd = x1 + } + -- open RawProduct rawP renaming (fst to x0 ; snd to x1) + module _ {Y : ℂ.Object} (p0 : ℂ [ Y , 𝒜 ]) (p1 : ℂ [ Y , ℬ ]) where + uy : isContr (Arrow (Y , p0 , p1) (X , x0 , x1)) + uy = uniq {Y , p0 , p1} + open Σ uy renaming (fst to Y→X ; snd to contractible) + open Σ Y→X renaming (fst to p0×p1 ; snd to cond) + ump : ∃![ f×g ] (ℂ [ x0 ∘ f×g ] ≡ p0 P.× ℂ [ x1 ∘ f×g ] ≡ p1) + ump = p0×p1 , cond , λ {f} cond-f → cong fst (contractible (f , cond-f)) + isP : IsProduct ℂ 𝒜 ℬ rawP + isP = record { ump = ump } + p : Product ℂ 𝒜 ℬ + p = record + { raw = rawP + ; isProduct = isP + } + g : Product ℂ 𝒜 ℬ → Terminal + g p = 𝒳 , t + where + open Product p renaming (object to X ; fst to x₀ ; snd to x₁) using () + module p = Product p + module isp = IsProduct p.isProduct + 𝒳 : Object + 𝒳 = X , x₀ , x₁ + module _ {𝒴 : Object} where + open Σ 𝒴 renaming (fst to Y) + open Σ (snd 𝒴) renaming (fst to y₀ ; snd to y₁) + ump = p.ump y₀ y₁ + open Σ ump renaming (fst to f') + open Σ (snd ump) renaming (fst to f'-cond) + 𝒻 : Arrow 𝒴 𝒳 + 𝒻 = f' , f'-cond + contractible : (f : Arrow 𝒴 𝒳) → 𝒻 ≡ f + contractible ff@(f , f-cond) = res + where + k : f' ≡ f + k = snd (snd ump) f-cond + prp : (a : ℂ.Arrow Y X) → isProp + ( (ℂ [ x₀ ∘ a ] ≡ y₀) + × (ℂ [ x₁ ∘ a ] ≡ y₁) + ) + prp f f0 f1 = Σ≡ + (ℂ.arrowsAreSets _ _ (fst f0) (fst f1)) + (ℂ.arrowsAreSets _ _ (snd f0) (snd f1)) + h : + ( λ i + → ℂ [ x₀ ∘ k i ] ≡ y₀ + × ℂ [ x₁ ∘ k i ] ≡ y₁ + ) [ f'-cond ≡ f-cond ] + h = lemPropF prp k + res : (f' , f'-cond) ≡ (f , f-cond) + res = Σ≡ k h + t : IsTerminal 𝒳 + t {𝒴} = 𝒻 , contractible + ve-re : ∀ x → g (f x) ≡ x + ve-re x = Propositionality.propTerminal _ _ + re-ve : ∀ p → f (g p) ≡ p + re-ve p = Product≡ e + where + module p = Product p + -- RawProduct does not have eta-equality. + e : Product.raw (f (g p)) ≡ Product.raw p + RawProduct.object (e i) = p.object + RawProduct.fst (e i) = p.fst + RawProduct.snd (e i) = p.snd + inv : AreInverses f g + inv = funExt ve-re , funExt re-ve propProduct : isProp (Product ℂ 𝒜 ℬ) propProduct = equivPreservesNType {n = ⟨-1⟩} lemma Propositionality.propTerminal @@ -348,10 +184,7 @@ module _ {ℓa ℓb : Level} {ℂ : Category ℓa ℓb} {A B : Category.Object module y = HasProducts y productEq : x.product ≡ y.product - productEq = funExt λ A → funExt λ B → Try0.propProduct _ _ + productEq = funExt λ A → funExt λ B → propProduct _ _ propHasProducts : isProp (HasProducts ℂ) propHasProducts x y i = record { product = productEq x y i } - -fmap≡ : {A : Set} {a0 a1 : A} {B : Set} → (f : A → B) → Path a0 a1 → Path (f a0) (f a1) -fmap≡ = cong diff --git a/src/Cat/Category/Yoneda.agda b/src/Cat/Category/Yoneda.agda index c02274b..1fbe990 100644 --- a/src/Cat/Category/Yoneda.agda +++ b/src/Cat/Category/Yoneda.agda @@ -9,9 +9,9 @@ open import Cat.Category.Functor open import Cat.Category.NaturalTransformation renaming (module Properties to F) using () - -open import Cat.Categories.Fun using (module Fun) +open import Cat.Categories.Opposite open import Cat.Categories.Sets hiding (presheaf) +open import Cat.Categories.Fun using (module Fun) -- There is no (small) category of categories. So we won't use _⇑_ from -- `HasExponential` From 8a0ea9f4a5f37d995696ba3da9e34d963459e825 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frederik=20Hangh=C3=B8j=20Iversen?= Date: Tue, 15 May 2018 17:11:01 +0200 Subject: [PATCH 06/33] Use darkorange for all bordercolors --- doc/implementation.tex | 39 ++++++++++++++++++++++----------------- doc/packages.tex | 6 ++++-- 2 files changed, 26 insertions(+), 19 deletions(-) diff --git a/doc/implementation.tex b/doc/implementation.tex index 75f2df7..94198b6 100644 --- a/doc/implementation.tex +++ b/doc/implementation.tex @@ -8,6 +8,7 @@ This implementation formalizes the following concepts: \begin{tabular}{ l l } Name & Link \\ \hline +Equivalences & \sourcelink{Cat.Equivalence} \\ Categories & \sourcelink{Cat.Category} \\ Functors & \sourcelink{Cat.Category.Functor} \\ Products & \sourcelink{Cat.Category.Product} \\ @@ -19,12 +20,9 @@ Monads & \sourcelink{Cat.Category.Monad} \\ Kleisli Monads & \sourcelink{Cat.Category.Monad.Kleisli} \\ Monoidal Monads & \sourcelink{Cat.Category.Monad.Monoidal} \\ Voevodsky's construction & \sourcelink{Cat.Category.Monad.Voevodsky} \\ -%% Categories & \null \\ -%% Opposite category & \sourcelink{Cat.Categories.Opposite} \\ Category of sets & \sourcelink{Cat.Categories.Sets} \\ Span category & \sourcelink{Cat.Categories.Span} \\ - %% \end{tabular} \end{center} % @@ -42,12 +40,16 @@ Monoids & \sourcelink{Cat.Category.Monoid} \\ \end{tabular} \end{center} % -As well as a range of various results about these. E.g. I have shown that the -category of sets has products. In the following I aim to demonstrate some of the -techniques employed in this formalization and in the interest of brevity I will -not detail all the things I have formalized. In stead, I have selected a parts -of this formalization that highlight some interesting proof techniques relevant -to doing proofs in Cubical Agda. +As well as a range of various results about these. E.g. I have shown +that the category of sets has products. In the following I aim to +demonstrate some of the techniques employed in this formalization and +in the interest of brevity I will not detail all the things I have +formalized. In stead, I have selected parts of this formalization that +highlight some interesting proof techniques relevant to doing proofs +in Cubical Agda. This chapter will focus on the definition of +\emph{categories}, \emph{equivalences}, the \emph{opposite category}, +the \emph{category of sets}, \emph{products}, the \emph{span category} +and the two formulations of \emph{monads}. One such technique that is pervasive to this formalization is the idea of distinguishing types with more or less homotopical structure. To do this I have @@ -792,16 +794,19 @@ proposition and then use $\lemPropF$. So we prove the generalization: But $\var{AreInverses}\ f\ g$ is a pair of equations on arrows, so we use $\propSig$ and the fact that both $A$ and $B$ are sets to close this proof. -\subsection{Category of categories} -Note that this category does in fact not exist. In stead I provide the -definition of the ``raw'' category as well as some of the laws. +%% \subsection{Category of categories} -Furthermore I provide some helpful lemmas about this raw category. For instance -I have shown what would be the exponential object in such a category. +%% Note that this category does in fact not exist. In stead I provide +%% the definition of the ``raw'' category as well as some of the laws. -These lemmas can be used to provide the actual exponential object in a context -where we have a witness to this being a category. This is useful if this library -is later extended to talk about higher categories. +%% Furthermore I provide some helpful lemmas about this raw category. +%% For instance I have shown what would be the exponential object in +%% such a category. + +%% These lemmas can be used to provide the actual exponential object +%% in a context where we have a witness to this being a category. This +%% is useful if this library is later extended to talk about higher +%% categories. \section{Products} \label{sec:products} diff --git a/doc/packages.tex b/doc/packages.tex index 20dddaa..6143bf0 100644 --- a/doc/packages.tex +++ b/doc/packages.tex @@ -3,13 +3,15 @@ \usepackage{natbib} \bibliographystyle{plain} +\usepackage{xcolor} \usepackage[ - hidelinks, + %% hidelinks, pdfusetitle, pdfsubject={category theory}, pdfkeywords={type theory, homotopy theory, category theory, agda}] {hyperref} - +\definecolor{darkorange}{HTML}{ff8c00} +\hypersetup{allbordercolors={darkorange}} \usepackage{graphicx} \usepackage{parskip} From c75a1d5d8b4ad52866d9ff34ec2d885facbce15f Mon Sep 17 00:00:00 2001 From: Andrea Vezzosi Date: Tue, 15 May 2018 17:21:57 +0200 Subject: [PATCH 07/33] commented out code with holes --- src/Cat/Categories/Fun.agda | 139 +++++++++++++------------- src/Cat/Category.agda | 2 +- src/Cat/Category/Monad/Voevodsky.agda | 1 + src/Cat/Category/Product.agda | 3 +- 4 files changed, 74 insertions(+), 71 deletions(-) diff --git a/src/Cat/Categories/Fun.agda b/src/Cat/Categories/Fun.agda index eb861e7..9a732f4 100644 --- a/src/Cat/Categories/Fun.agda +++ b/src/Cat/Categories/Fun.agda @@ -1,6 +1,7 @@ {-# OPTIONS --allow-unsolved-metas --cubical --caching #-} module Cat.Categories.Fun where + open import Cat.Prelude open import Cat.Equivalence @@ -52,14 +53,14 @@ module Fun {ℓc ℓc' ℓd ℓd' : Level} (ℂ : Category ℓc ℓc') (𝔻 : C lem : coe (pp {C}) 𝔻.identity ≡ f→g lem = trans (𝔻.9-1-9-right {b = Functor.omap F C} 𝔻.identity p*) 𝔻.rightIdentity - idToNatTrans : NaturalTransformation F G - idToNatTrans = (λ C → coe pp 𝔻.identity) , λ f → begin - coe pp 𝔻.identity 𝔻.<<< F.fmap f ≡⟨ cong (𝔻._<<< F.fmap f) lem ⟩ - -- Just need to show that f→g is a natural transformation - -- I know that it has an inverse; g→f - f→g 𝔻.<<< F.fmap f ≡⟨ {!lem!} ⟩ - G.fmap f 𝔻.<<< f→g ≡⟨ cong (G.fmap f 𝔻.<<<_) (sym lem) ⟩ - G.fmap f 𝔻.<<< coe pp 𝔻.identity ∎ + -- idToNatTrans : NaturalTransformation F G + -- idToNatTrans = (λ C → coe pp 𝔻.identity) , λ f → begin + -- coe pp 𝔻.identity 𝔻.<<< F.fmap f ≡⟨ cong (𝔻._<<< F.fmap f) lem ⟩ + -- -- Just need to show that f→g is a natural transformation + -- -- I know that it has an inverse; g→f + -- f→g 𝔻.<<< F.fmap f ≡⟨ {!lem!} ⟩ + -- G.fmap f 𝔻.<<< f→g ≡⟨ cong (G.fmap f 𝔻.<<<_) (sym lem) ⟩ + -- G.fmap f 𝔻.<<< coe pp 𝔻.identity ∎ module _ {A B : Functor ℂ 𝔻} where module A = Functor A @@ -92,70 +93,70 @@ module Fun {ℓc ℓc' ℓd ℓd' : Level} (ℂ : Category ℓc ℓc') (𝔻 : C U : (F : ℂ.Object → 𝔻.Object) → Set _ U F = {A B : ℂ.Object} → ℂ [ A , B ] → 𝔻 [ F A , F B ] - module _ - (omap : ℂ.Object → 𝔻.Object) - (p : A.omap ≡ omap) - where - D : Set _ - D = ( fmap : U omap) - → ( let - raw-B : RawFunctor ℂ 𝔻 - raw-B = record { omap = omap ; fmap = fmap } - ) - → (isF-B' : IsFunctor ℂ 𝔻 raw-B) - → ( let - B' : Functor ℂ 𝔻 - B' = record { raw = raw-B ; isFunctor = isF-B' } - ) - → (iso' : A ≊ B') → PathP (λ i → U (p i)) A.fmap fmap - -- D : Set _ - -- D = PathP (λ i → U (p i)) A.fmap fmap - -- eeq : (λ f → A.fmap f) ≡ fmap - -- eeq = funExtImp (λ A → funExtImp (λ B → funExt (λ f → isofmap {A} {B} f))) - -- where - -- module _ {X : ℂ.Object} {Y : ℂ.Object} (f : ℂ [ X , Y ]) where - -- isofmap : A.fmap f ≡ fmap f - -- isofmap = {!ap!} - d : D A.omap refl - d = res - where - module _ - ( fmap : U A.omap ) - ( let - raw-B : RawFunctor ℂ 𝔻 - raw-B = record { omap = A.omap ; fmap = fmap } - ) - ( isF-B' : IsFunctor ℂ 𝔻 raw-B ) - ( let - B' : Functor ℂ 𝔻 - B' = record { raw = raw-B ; isFunctor = isF-B' } - ) - ( iso' : A ≊ B' ) - where - module _ {X Y : ℂ.Object} (f : ℂ [ X , Y ]) where - step : {!!} 𝔻.≊ {!!} - step = {!!} - resres : A.fmap {X} {Y} f ≡ fmap {X} {Y} f - resres = {!!} - res : PathP (λ i → U A.omap) A.fmap fmap - res i {X} {Y} f = resres f i + -- module _ + -- (omap : ℂ.Object → 𝔻.Object) + -- (p : A.omap ≡ omap) + -- where + -- D : Set _ + -- D = ( fmap : U omap) + -- → ( let + -- raw-B : RawFunctor ℂ 𝔻 + -- raw-B = record { omap = omap ; fmap = fmap } + -- ) + -- → (isF-B' : IsFunctor ℂ 𝔻 raw-B) + -- → ( let + -- B' : Functor ℂ 𝔻 + -- B' = record { raw = raw-B ; isFunctor = isF-B' } + -- ) + -- → (iso' : A ≊ B') → PathP (λ i → U (p i)) A.fmap fmap + -- -- D : Set _ + -- -- D = PathP (λ i → U (p i)) A.fmap fmap + -- -- eeq : (λ f → A.fmap f) ≡ fmap + -- -- eeq = funExtImp (λ A → funExtImp (λ B → funExt (λ f → isofmap {A} {B} f))) + -- -- where + -- -- module _ {X : ℂ.Object} {Y : ℂ.Object} (f : ℂ [ X , Y ]) where + -- -- isofmap : A.fmap f ≡ fmap f + -- -- isofmap = {!ap!} + -- d : D A.omap refl + -- d = res + -- where + -- module _ + -- ( fmap : U A.omap ) + -- ( let + -- raw-B : RawFunctor ℂ 𝔻 + -- raw-B = record { omap = A.omap ; fmap = fmap } + -- ) + -- ( isF-B' : IsFunctor ℂ 𝔻 raw-B ) + -- ( let + -- B' : Functor ℂ 𝔻 + -- B' = record { raw = raw-B ; isFunctor = isF-B' } + -- ) + -- ( iso' : A ≊ B' ) + -- where + -- module _ {X Y : ℂ.Object} (f : ℂ [ X , Y ]) where + -- step : {!!} 𝔻.≊ {!!} + -- step = {!!} + -- resres : A.fmap {X} {Y} f ≡ fmap {X} {Y} f + -- resres = {!!} + -- res : PathP (λ i → U A.omap) A.fmap fmap + -- res i {X} {Y} f = resres f i - fmapEq : PathP (λ i → U (omapEq i)) A.fmap B.fmap - fmapEq = pathJ D d B.omap omapEq B.fmap B.isFunctor iso + -- fmapEq : PathP (λ i → U (omapEq i)) A.fmap B.fmap + -- fmapEq = pathJ D d B.omap omapEq B.fmap B.isFunctor iso - rawEq : A.raw ≡ B.raw - rawEq i = record { omap = omapEq i ; fmap = fmapEq i } + -- rawEq : A.raw ≡ B.raw + -- rawEq i = record { omap = omapEq i ; fmap = fmapEq i } - private - f : (A ≡ B) → (A ≊ B) - f p = idToNatTrans p , idToNatTrans (sym p) , NaturalTransformation≡ A A (funExt (λ C → {!!})) , {!!} - g : (A ≊ B) → (A ≡ B) - g = Functor≡ ∘ rawEq - inv : AreInverses f g - inv = {!funExt λ p → ?!} , {!!} - - iso : (A ≡ B) ≅ (A ≊ B) - iso = f , g , inv + -- private + -- f : (A ≡ B) → (A ≊ B) + -- f p = idToNatTrans p , idToNatTrans (sym p) , NaturalTransformation≡ A A (funExt (λ C → {!!})) , {!!} + -- g : (A ≊ B) → (A ≡ B) + -- g = Functor≡ ∘ rawEq + -- inv : AreInverses f g + -- inv = {!funExt λ p → ?!} , {!!} + postulate + iso : (A ≡ B) ≅ (A ≊ B) +-- iso = f , g , inv univ : (A ≡ B) ≃ (A ≊ B) univ = fromIsomorphism _ _ iso diff --git a/src/Cat/Category.agda b/src/Cat/Category.agda index 274f94e..ed453c2 100644 --- a/src/Cat/Category.agda +++ b/src/Cat/Category.agda @@ -44,7 +44,7 @@ open Cat.Equivalence -- 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 +-- no-eta-equality field Object : Set ℓa Arrow : Object → Object → Set ℓb diff --git a/src/Cat/Category/Monad/Voevodsky.agda b/src/Cat/Category/Monad/Voevodsky.agda index abc8438..0ad3d90 100644 --- a/src/Cat/Category/Monad/Voevodsky.agda +++ b/src/Cat/Category/Monad/Voevodsky.agda @@ -4,6 +4,7 @@ This module provides construction 2.3 in [voe] {-# OPTIONS --cubical --caching #-} module Cat.Category.Monad.Voevodsky where + open import Cat.Prelude open import Cat.Category diff --git a/src/Cat/Category/Product.agda b/src/Cat/Category/Product.agda index 4856668..2cf55ed 100644 --- a/src/Cat/Category/Product.agda +++ b/src/Cat/Category/Product.agda @@ -1,6 +1,7 @@ {-# OPTIONS --cubical --caching #-} module Cat.Category.Product where + open import Cat.Prelude as P hiding (_×_ ; fst ; snd) open import Cat.Equivalence @@ -11,7 +12,7 @@ module _ {ℓa ℓb : Level} (ℂ : Category ℓa ℓb) where module _ (A B : Object) where record RawProduct : Set (ℓa ⊔ ℓb) where - no-eta-equality + -- no-eta-equality field object : Object fst : ℂ [ object , A ] From d33c814e7887643ca6dcf38b9c310e0be09b6a5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frederik=20Hangh=C3=B8j=20Iversen?= Date: Tue, 15 May 2018 18:34:25 +0200 Subject: [PATCH 08/33] Add introduction --- doc/introduction.tex | 150 +++++++++++++++++++++++++++---------------- 1 file changed, 95 insertions(+), 55 deletions(-) diff --git a/doc/introduction.tex b/doc/introduction.tex index 31a8ce3..b29d6b5 100644 --- a/doc/introduction.tex +++ b/doc/introduction.tex @@ -1,8 +1,44 @@ \chapter{Introduction} +This thesis is a case-study in the application of Cubical Agda in the +context of category theory. At the center of this is the notion of +\nomenindex{equality}. In type-theory there are two pervasive notions +of equality: \nomenindex{judgmental equality} and +\nomenindex{propositional equality}. Judgmental equality is a property +of the type system, it is a property that is automatically checked by +a type checker. As such there are some properties judgmental +equalities must crucially have. It must be \nomenindex{decidable}, +\nomenindex{sound}, enjoy \nomenindex{canonicity} and be a +\nomen{congruence relation}. Being decidable simply means that that an +algorithm exists to decide whether two terms are equal. For any +practical implementation the decidability must also be effectively +computable. Soundness means that things judged to be equal actually +\emph{are} considered equal. It must be a congruence relation because +otherwise the relation certainly does not adhere to our notion of +equality. One would be able to conclude things like: $x \nequiv y +\rightarrow f\ x \equiv f\ y$. Canonicity will be explained later in +this introduction after we've seen an example of judgmental- and +propositional equality at play for a simple example.\TODO{How to + motivate canonicity for equality}. + +For propositional equality the decidability requirement is relaxed. It +is not in general possible to decide the correctness of logical +propositions (cf. Hilbert's \nomen{entscheidigungsproblem}). +Propositional equality are provided by the developer. When introducing +definitions this report will use the notation $\defeq$. Judgmental +equalities written $=$. For propositional equalities the notation +$\equiv$ is used. + +The usual notion of propositional equality in \nomen{Intensional Type + Theory} (ITT) is quite restrictive. In the next section a few +motivating examples will highlight this. There exist techniques to +circumvent these problems, as we shall see. This thesis will explore +an extension to Agda that redefines the notion of propositional +equality and as such is an alternative to these other techniques. +% \section{Motivating examples} % -In the following two sections I present two examples that illustrate some -limitations inherent in ITT and -- by extension -- Agda. +In the following two sections I present two examples that illustrate +some limitations inherent in ITT and -- by extension -- Agda. % \subsection{Functional extensionality} \label{sec:functional-extensionality}% @@ -18,9 +54,9 @@ Consider the functions: \end{equation*}% \end{multicols}% % -The term $n + 0$ is +The term $n + 0$ is \nomenindex{definitionally} equal to $n$, which we -write as $n + 0 = n$. This is also called +write as $n + 0 = n$. This is also called \nomenindex{judgmental equality}. We call it definitional equality because the \emph{equality} arises from the \emph{definition} of $+$ which is: @@ -39,35 +75,43 @@ as $n + 0 \equiv n$. Propositional equality means that there is a proof that exhibits this relation. Since equality is a transitive relation we have that $n + 0 \equiv 0 + n$. -Unfortunately we don't have $f \equiv g$.\footnote{Actually showing this is -outside the scope of this text. Essentially it would involve giving a model -for our type theory that validates all our axioms but where $f \equiv g$ is -not true.} There is no way to construct a proof asserting the obvious -equivalence of $f$ and $g$ -- even though we can prove them equal for all -points. This is exactly the notion of equality of functions that we are -interested in; that they are equal for all inputs. We call this +Unfortunately we don't have $f \equiv g$. There is no way to construct +a proof asserting the obvious equivalence of $f$ and $g$. Actually +showing this is outside the scope of this text. Essentially it would +involve giving a model for our type theory that validates all our +axioms but where $f \equiv g$ is not true. We cannot show that they +are equal, even though we can prove them equal for all points. For +functions this is exactly the notion of equality that we are +interested in: Functions are considered equal when they are equal for +all inputs. This is called \nomenindex{point wise equality}, where the +\emph{points} of a function refer to its arguments. -\nomenindex{point-wise equality}, where the \emph{points} of a function refers -to its arguments. - -In the context of category theory functional extensionality is e.g. needed to -show that representable functors are indeed functors. The representable functor -for a category $\bC$ and a fixed object in $A \in \bC$ is defined to be: -% -\begin{align*} -\fmap \defeq \lambda\ X \to \Hom_{\bC}(A, X) -\end{align*} -% -The proof obligation that this satisfies the identity law of functors -($\fmap\ \idFun \equiv \idFun$) thus becomes: -% -\begin{align*} -\Hom(A, \idFun_{\bX}) = (\lambda\ g \to \idFun \comp g) \equiv \idFun_{\Sets} -\end{align*} -% -One needs functional extensionality to ``go under'' the function arrow and apply -the (left) identity law of the underlying category to prove $\idFun \comp g -\equiv g$ and thus close the goal. +%% In the context of category theory functional extensionality is e.g. +%% needed to show that representable functors are indeed functors. The +%% representable functor is defined for a fixed category $\bC$ and an +%% object $X \in \bC$. It's map on objects is defined thus: +%% % +%% \begin{align*} +%% \lambda\ A \to \Arrow\ X\ A +%% \end{align*} +%% % +%% That is, it maps objects to arrows. So, it's map on arrows must map an arrow $\Arrow\ A\ B$ to an +%% The map on objects is defined thus: +%% % +%% \begin{align*} +%% \lambda f \to +%% \end{align*} +%% % +%% The proof obligation that this satisfies the identity law of functors +%% ($\fmap\ \idFun \equiv \idFun$) thus becomes: +%% % +%% \begin{align*} +%% \Hom(A, \idFun_{\bX}) = (\lambda\ g \to \idFun \comp g) \equiv \idFun_{\Sets} +%% \end{align*} +%% % +%% One needs functional extensionality to ``go under'' the function arrow and apply +%% the (left) identity law of the underlying category to prove $\idFun \comp g +%% \equiv g$ and thus close the goal. % \subsection{Equality of isomorphic types} % @@ -75,7 +119,7 @@ Let $\top$ denote the unit type -- a type with a single constructor. In the propositions as types interpretation of type theory $\top$ is the proposition that is always true. The type $A \x \top$ and $A$ has an element for each $a \tp A$. So in a sense they have the same shape -(Greek; +(Greek; \nomenindex{isomorphic}). The second element of the pair does not add any ``interesting information''. It can be useful to identify such types. In fact, it is quite commonplace in mathematics. Say we look at @@ -87,10 +131,11 @@ be performed in ITT. More specifically what we are interested in is a way of identifying -\nomenindex{equivalent} types. I will return to the definition of equivalence later -in section \S\ref{sec:equiv}, but for now it is sufficient to think of an -equivalence as a one-to-one correspondence. We write $A \simeq B$ to assert that -$A$ and $B$ are equivalent types. The principle of univalence says that: +\nomenindex{equivalent} types. I will return to the definition of +equivalence later in section \S\ref{sec:equiv}, but for now it is +sufficient to think of an equivalence as a one-to-one correspondence. +We write $A \simeq B$ to assert that $A$ and $B$ are equivalent types. +The principle of univalence says that: % $$\mathit{univalence} \tp (A \simeq B) \simeq (A \equiv B)$$ % @@ -119,25 +164,20 @@ implementations of category theory in Agda: % \begin{itemize} \item + A formalization in Agda using the setoid approach: \url{https://github.com/copumpkin/categories} - - A formalization in Agda using the setoid approach \item + A formalization in Agda with univalence and functional + extensionality as postulates: \url{https://github.com/pcapriotti/agda-categories} - - A formalization in Agda with univalence and functional extensionality as - postulates. \item + A formalization in Coq in the homotopic setting: \url{https://github.com/HoTT/HoTT/tree/master/theories/Categories} - - A formalization in Coq in the homotopic setting \item - \url{https://github.com/mortberg/cubicaltt} - A formalization in CubicalTT - a language designed for cubical type theory. Formalizes many different things, but only a few concepts from category - theory. - + theory: + \url{https://github.com/mortberg/cubicaltt} \end{itemize} % The contribution of this thesis is to explore how working in a cubical setting @@ -158,7 +198,7 @@ canonical form. Another approach is to use the \emph{setoid interpretation} of type theory (\cite{hofmann-1995,huber-2016}). With this approach one works -with +with \nomenindex{extensional sets} $(X, \sim)$, that is a type $X \tp \MCU$ and an equivalence relation $\sim\ \tp X \to X \to \MCU$ on that type. Under the setoid interpretation the equivalence relation serve as a @@ -178,18 +218,18 @@ inherently `local' to the extensional set $(X , \sim)$. \TODO{Talk a bit about terminology. Find a good place to stuff this little section.} -In the remainder of this paper I will use the term +In the remainder of this paper I will use the term \nomenindex{Type} to describe -- well, types. Thereby diverging from the notation in Agda where the keyword -\texttt{Set} refers to types. +\texttt{Set} refers to types. \nomenindex{Set} on the other hand shall refer to the homotopical notion of a set. I will also leave all universe levels implicit. -And I use the term +And I use the term \nomenindex{arrow} to refer to morphisms in a category, -whereas the terms -\nomenindex{morphism}, -\nomenindex{map} or +whereas the terms +\nomenindex{morphism}, +\nomenindex{map} or \nomenindex{function} shall be reserved for talking about type theoretic functions; i.e. functions in Agda. From 9f7a13b5daae242d618116914f41b507fb18baad Mon Sep 17 00:00:00 2001 From: Andrea Vezzosi Date: Wed, 16 May 2018 10:41:41 +0200 Subject: [PATCH 09/33] no-eta-equality for monads speeds up Voevodsky --- src/Cat/Category/Monad/Kleisli.agda | 1 + src/Cat/Category/Monad/Monoidal.agda | 1 + src/Cat/Category/Monad/Voevodsky.agda | 130 +++++++++++--------------- 3 files changed, 54 insertions(+), 78 deletions(-) diff --git a/src/Cat/Category/Monad/Kleisli.agda b/src/Cat/Category/Monad/Kleisli.agda index e0ebf86..366886b 100644 --- a/src/Cat/Category/Monad/Kleisli.agda +++ b/src/Cat/Category/Monad/Kleisli.agda @@ -230,6 +230,7 @@ record IsMonad (raw : RawMonad) : Set ℓ where m ∎ record Monad : Set ℓ where + no-eta-equality field raw : RawMonad isMonad : IsMonad raw diff --git a/src/Cat/Category/Monad/Monoidal.agda b/src/Cat/Category/Monad/Monoidal.agda index f5b20ad..11f1dbc 100644 --- a/src/Cat/Category/Monad/Monoidal.agda +++ b/src/Cat/Category/Monad/Monoidal.agda @@ -123,6 +123,7 @@ record IsMonad (raw : RawMonad) : Set ℓ where ∎ record Monad : Set ℓ where + no-eta-equality field raw : RawMonad isMonad : IsMonad raw diff --git a/src/Cat/Category/Monad/Voevodsky.agda b/src/Cat/Category/Monad/Voevodsky.agda index 0ad3d90..0d38567 100644 --- a/src/Cat/Category/Monad/Voevodsky.agda +++ b/src/Cat/Category/Monad/Voevodsky.agda @@ -25,6 +25,7 @@ module voe {ℓa ℓb : Level} (ℂ : Category ℓa ℓb) where module §2-3 (omap : Object → Object) (pure : {X : Object} → Arrow X (omap X)) where record §1 : Set ℓ where + no-eta-equality open M field @@ -75,12 +76,11 @@ module voe {ℓa ℓb : Level} (ℂ : Category ℓa ℓb) where isMonad : IsMonad rawMnd toMonad : Monad - toMonad = record - { raw = rawMnd - ; isMonad = isMonad - } + toMonad .Monad.raw = rawMnd + toMonad .Monad.isMonad = isMonad record §2 : Set ℓ where + no-eta-equality open K field @@ -97,28 +97,24 @@ module voe {ℓa ℓb : Level} (ℂ : Category ℓa ℓb) where isMonad : IsMonad rawMnd toMonad : Monad - toMonad = record - { raw = rawMnd - ; isMonad = isMonad - } + toMonad .Monad.raw = rawMnd + toMonad .Monad.isMonad = isMonad - §1-fromMonad : (m : M.Monad) → §2-3.§1 (M.Monad.Romap m) (λ {X} → M.Monad.pureT m X) - §1-fromMonad m = record - { fmap = Functor.fmap R - ; RisFunctor = Functor.isFunctor R - ; pureN = pureN - ; join = λ {X} → joinT X - ; joinN = joinN - ; isMonad = M.Monad.isMonad m - } - where + module _ (m : M.Monad) where open M.Monad m + §1-fromMonad : §2-3.§1 (M.Monad.Romap m) (λ {X} → M.Monad.pureT m X) + §1-fromMonad .§2-3.§1.fmap = Functor.fmap R + §1-fromMonad .§2-3.§1.RisFunctor = Functor.isFunctor R + §1-fromMonad .§2-3.§1.pureN = pureN + §1-fromMonad .§2-3.§1.join {X} = joinT X + §1-fromMonad .§2-3.§1.joinN = joinN + §1-fromMonad .§2-3.§1.isMonad = M.Monad.isMonad m + + §2-fromMonad : (m : K.Monad) → §2-3.§2 (K.Monad.omap m) (K.Monad.pure m) - §2-fromMonad m = record - { bind = K.Monad.bind m - ; isMonad = K.Monad.isMonad m - } + §2-fromMonad m .§2-3.§2.bind = K.Monad.bind m + §2-fromMonad m .§2-3.§2.isMonad = K.Monad.isMonad m -- | In the following we seek to transform the equivalence `Monoidal≃Kleisli` -- | to talk about voevodsky's construction. @@ -145,65 +141,43 @@ module voe {ℓa ℓb : Level} (ℂ : Category ℓa ℓb) where back = §1-fromMonad ∘ Kleisli→Monoidal ∘ §2-3.§2.toMonad forthEq : ∀ m → (forth ∘ back) m ≡ m - forthEq m = begin - (forth ∘ back) m ≡⟨⟩ - -- In full gory detail: - ( §2-fromMonad - ∘ Monoidal→Kleisli - ∘ §2-3.§1.toMonad - ∘ §1-fromMonad - ∘ Kleisli→Monoidal - ∘ §2-3.§2.toMonad - ) m ≡⟨⟩ -- fromMonad and toMonad are inverses - ( §2-fromMonad - ∘ Monoidal→Kleisli - ∘ Kleisli→Monoidal - ∘ §2-3.§2.toMonad - ) m ≡⟨ cong (λ φ → φ m) t ⟩ - -- Monoidal→Kleisli and Kleisli→Monoidal are inverses - -- I should be able to prove this using congruence and `lem` below. - ( §2-fromMonad - ∘ §2-3.§2.toMonad - ) m ≡⟨⟩ - ( §2-fromMonad - ∘ §2-3.§2.toMonad - ) m ≡⟨⟩ -- fromMonad and toMonad are inverses - m ∎ + forthEq m = trans + (trans (cong-d (§2-fromMonad ∘ Monoidal→Kleisli) (lemmaz (Kleisli→Monoidal (§2-3.§2.toMonad m)))) + (cong-d (\ φ → §2-fromMonad (φ (§2-3.§2.toMonad m))) re-ve)) + lemma where - t' : ((Monoidal→Kleisli ∘ Kleisli→Monoidal) ∘ §2-3.§2.toMonad {omap} {pure}) - ≡ §2-3.§2.toMonad - t' = cong (\ φ → φ ∘ §2-3.§2.toMonad) re-ve - t : (§2-fromMonad ∘ (Monoidal→Kleisli ∘ Kleisli→Monoidal) ∘ §2-3.§2.toMonad {omap} {pure}) - ≡ (§2-fromMonad ∘ §2-3.§2.toMonad) - t = cong-d (\ f → §2-fromMonad ∘ f) t' - u : (§2-fromMonad ∘ (Monoidal→Kleisli ∘ Kleisli→Monoidal) ∘ §2-3.§2.toMonad) m - ≡ (§2-fromMonad ∘ §2-3.§2.toMonad) m - u = cong (\ φ → φ m) t + lemma : (§2-fromMonad ∘ §2-3.§2.toMonad) m ≡ m + §2-3.§2.bind (lemma i) = §2-3.§2.bind m + §2-3.§2.isMonad (lemma i) = §2-3.§2.isMonad m + lemmaz : ∀ m → §2-3.§1.toMonad (§1-fromMonad m) ≡ m + M.Monad.raw (lemmaz m i) = M.Monad.raw m + M.Monad.isMonad (lemmaz m i) = M.Monad.isMonad m backEq : ∀ m → (back ∘ forth) m ≡ m - backEq m = begin - (back ∘ forth) m ≡⟨⟩ - ( §1-fromMonad - ∘ Kleisli→Monoidal - ∘ §2-3.§2.toMonad - ∘ §2-fromMonad - ∘ Monoidal→Kleisli - ∘ §2-3.§1.toMonad - ) m ≡⟨⟩ -- fromMonad and toMonad are inverses - ( §1-fromMonad - ∘ Kleisli→Monoidal - ∘ Monoidal→Kleisli - ∘ §2-3.§1.toMonad - ) m ≡⟨ cong (λ φ → φ m) t ⟩ -- Monoidal→Kleisli and Kleisli→Monoidal are inverses - ( §1-fromMonad - ∘ §2-3.§1.toMonad - ) m ≡⟨⟩ -- fromMonad and toMonad are inverses - m ∎ - where - t : §1-fromMonad ∘ Kleisli→Monoidal ∘ Monoidal→Kleisli ∘ §2-3.§1.toMonad - ≡ §1-fromMonad ∘ §2-3.§1.toMonad - -- Why does `re-ve` not satisfy this goal? - t i m = §1-fromMonad (ve-re i (§2-3.§1.toMonad m)) + backEq m = trans (cong-d (§1-fromMonad ∘ Kleisli→Monoidal) (lemma (Monoidal→Kleisli (§2-3.§1.toMonad m)))) + (trans (cong-d (\ φ → §1-fromMonad (φ (§2-3.§1.toMonad m))) ve-re) + lemmaz) + where + -- rhs = §1-fromMonad (Kleisli→Monoidal ((Monoidal→Kleisli (§2-3.§1.toMonad m)))) + -- foo : §1-fromMonad (Kleisli→Monoidal (§2-3.§2.toMonad (§2-fromMonad (Monoidal→Kleisli (§2-3.§1.toMonad m))))) + -- ≡ §1-fromMonad (Kleisli→Monoidal ((Monoidal→Kleisli (§2-3.§1.toMonad m)))) + -- §2-3.§1.fmap (foo i) = §2-3.§1.fmap rhs + -- §2-3.§1.join (foo i) = §2-3.§1.join rhs + -- §2-3.§1.RisFunctor (foo i) = §2-3.§1.RisFunctor rhs + -- §2-3.§1.pureN (foo i) = §2-3.§1.pureN rhs + -- §2-3.§1.joinN (foo i) = §2-3.§1.joinN rhs + -- §2-3.§1.isMonad (foo i) = §2-3.§1.isMonad rhs + + lemmaz : §1-fromMonad (§2-3.§1.toMonad m) ≡ m + §2-3.§1.fmap (lemmaz i) = §2-3.§1.fmap m + §2-3.§1.join (lemmaz i) = §2-3.§1.join m + §2-3.§1.RisFunctor (lemmaz i) = §2-3.§1.RisFunctor m + §2-3.§1.pureN (lemmaz i) = §2-3.§1.pureN m + §2-3.§1.joinN (lemmaz i) = §2-3.§1.joinN m + §2-3.§1.isMonad (lemmaz i) = §2-3.§1.isMonad m + lemma : ∀ m → §2-3.§2.toMonad (§2-fromMonad m) ≡ m + K.Monad.raw (lemma m i) = K.Monad.raw m + K.Monad.isMonad (lemma m i) = K.Monad.isMonad m voe-isEquiv : isEquiv (§2-3.§1 omap pure) (§2-3.§2 omap pure) forth voe-isEquiv = gradLemma forth back forthEq backEq From 47c881ba2a760a4ea3520df62620cca836f9fede Mon Sep 17 00:00:00 2001 From: Andrea Vezzosi Date: Wed, 16 May 2018 10:50:56 +0200 Subject: [PATCH 10/33] Voe: gone back to equational reasoning, as it's fairly cheap now. --- src/Cat/Category/Monad/Voevodsky.agda | 36 +++++++++++++++++++++------ 1 file changed, 29 insertions(+), 7 deletions(-) diff --git a/src/Cat/Category/Monad/Voevodsky.agda b/src/Cat/Category/Monad/Voevodsky.agda index 0d38567..705bc38 100644 --- a/src/Cat/Category/Monad/Voevodsky.agda +++ b/src/Cat/Category/Monad/Voevodsky.agda @@ -141,10 +141,19 @@ module voe {ℓa ℓb : Level} (ℂ : Category ℓa ℓb) where back = §1-fromMonad ∘ Kleisli→Monoidal ∘ §2-3.§2.toMonad forthEq : ∀ m → (forth ∘ back) m ≡ m - forthEq m = trans - (trans (cong-d (§2-fromMonad ∘ Monoidal→Kleisli) (lemmaz (Kleisli→Monoidal (§2-3.§2.toMonad m)))) - (cong-d (\ φ → §2-fromMonad (φ (§2-3.§2.toMonad m))) re-ve)) - lemma + forthEq m = begin + §2-fromMonad + (Monoidal→Kleisli + (§2-3.§1.toMonad + (§1-fromMonad (Kleisli→Monoidal (§2-3.§2.toMonad m))))) + ≡⟨ cong-d (§2-fromMonad ∘ Monoidal→Kleisli) (lemmaz (Kleisli→Monoidal (§2-3.§2.toMonad m))) ⟩ + §2-fromMonad + ((Monoidal→Kleisli ∘ Kleisli→Monoidal) + (§2-3.§2.toMonad m)) + ≡⟨ (cong-d (\ φ → §2-fromMonad (φ (§2-3.§2.toMonad m))) re-ve) ⟩ + (§2-fromMonad ∘ §2-3.§2.toMonad) m + ≡⟨ lemma ⟩ + m ∎ where lemma : (§2-fromMonad ∘ §2-3.§2.toMonad) m ≡ m §2-3.§2.bind (lemma i) = §2-3.§2.bind m @@ -154,10 +163,23 @@ module voe {ℓa ℓb : Level} (ℂ : Category ℓa ℓb) where M.Monad.isMonad (lemmaz m i) = M.Monad.isMonad m backEq : ∀ m → (back ∘ forth) m ≡ m - backEq m = trans (cong-d (§1-fromMonad ∘ Kleisli→Monoidal) (lemma (Monoidal→Kleisli (§2-3.§1.toMonad m)))) - (trans (cong-d (\ φ → §1-fromMonad (φ (§2-3.§1.toMonad m))) ve-re) - lemmaz) + backEq m = begin + §1-fromMonad + (Kleisli→Monoidal + (§2-3.§2.toMonad + (§2-fromMonad (Monoidal→Kleisli (§2-3.§1.toMonad m))))) + ≡⟨ cong-d (§1-fromMonad ∘ Kleisli→Monoidal) (lemma (Monoidal→Kleisli (§2-3.§1.toMonad m))) ⟩ + §1-fromMonad + ((Kleisli→Monoidal ∘ Monoidal→Kleisli) + (§2-3.§1.toMonad m)) + ≡⟨ (cong-d (\ φ → §1-fromMonad (φ (§2-3.§1.toMonad m))) ve-re) ⟩ + §1-fromMonad (§2-3.§1.toMonad m) + ≡⟨ lemmaz ⟩ + m ∎ where + -- having eta equality on causes roughly the same work as checking this proof of foo, + -- which is quite expensive because it ends up reducing complex terms. + -- rhs = §1-fromMonad (Kleisli→Monoidal ((Monoidal→Kleisli (§2-3.§1.toMonad m)))) -- foo : §1-fromMonad (Kleisli→Monoidal (§2-3.§2.toMonad (§2-fromMonad (Monoidal→Kleisli (§2-3.§1.toMonad m))))) -- ≡ §1-fromMonad (Kleisli→Monoidal ((Monoidal→Kleisli (§2-3.§1.toMonad m)))) From be88602d24cb1476bc952a7337d9a216d3fe96e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frederik=20Hangh=C3=B8j=20Iversen?= Date: Wed, 16 May 2018 11:01:07 +0200 Subject: [PATCH 11/33] Fix spacing after 'e.g.' and 'i.e.' --- doc/cubical.tex | 6 +- doc/discussion.tex | 2 +- doc/halftime.tex | 2 +- doc/implementation.tex | 10 +- doc/introduction.tex | 20 ++-- doc/presentation.tex | 236 +++++++++++++++++++++++++++++++++++++++++ doc/title.tex | 95 +++++++++++++++++ 7 files changed, 351 insertions(+), 20 deletions(-) create mode 100644 doc/presentation.tex create mode 100644 doc/title.tex diff --git a/doc/cubical.tex b/doc/cubical.tex index a5d8135..6e07ac9 100644 --- a/doc/cubical.tex +++ b/doc/cubical.tex @@ -61,7 +61,7 @@ $I$. I will sometimes refer to $P$ as the \nomenindex{path space} of some path $ \Path\ P\ a\ b$. By this token $P\ 0$ then corresponds to the type at the left-endpoint and $P\ 1$ as the type at the right-endpoint. The type is called $\Path$ because it is connected with paths in homotopy theory. The intuition -behind this is that $\Path$ describes paths in $\MCU$ -- i.e. between types. For +behind this is that $\Path$ describes paths in $\MCU$ -- i.e.\ between types. For a path $p$ for the point $p\ i$ the index $i$ describes how far along the path one has moved. An inhabitant of $\Path\ P\ a_0\ a_1$ is a (dependent-) function, $p$, from the index-space to the path space: @@ -104,7 +104,7 @@ With this definition we can also recover reflexivity. That is, for any $A \tp Here the path space is $P \defeq \lambda i \to A$ and it satsifies $P\ i = A$ definitionally. So to inhabit it, is to give a path $I \to A$ which is judgmentally $a$ at either endpoint. This is satisfied by the constant path; -i.e. the path that stays at $a$ at any index $i$. +i.e.\ the path that stays at $a$ at any index $i$. It is also surpisingly easy to show functional extensionality with which we can construct a path between $f$ and $g$ -- the functions defined in the @@ -207,7 +207,7 @@ Then comes the set of homotopical sets: \end{equation} % I will not give an example of a set at this point. It turns out that proving -e.g. $\isProp\ \bN$ is not so straight-forward (see \cite[\S3.1.4]{hott-2013}). +e.g.\ $\isProp\ \bN$ is not so straight-forward (see \cite[\S3.1.4]{hott-2013}). There will be examples of sets later in this report. At this point it should be noted that the term ``set'' is somewhat conflated; there is the notion of sets from set-theory, in Agda types are denoted \texttt{Set}. I will use it diff --git a/doc/discussion.tex b/doc/discussion.tex index 771d4ef..58c687c 100644 --- a/doc/discussion.tex +++ b/doc/discussion.tex @@ -15,7 +15,7 @@ formalized this common result about monads: By transporting this to the Kleisli formulation we get a result that we can use to compute with. This is particularly useful because the Kleisli formulation -will be more familiar to programmers e.g. those coming from a background in +will be more familiar to programmers e.g.\ those coming from a background in Haskell. Whereas the theory usually talks about monoidal monads. \TODO{Mention that with postulates we cannot do this} diff --git a/doc/halftime.tex b/doc/halftime.tex index ca6d9a9..49cb880 100644 --- a/doc/halftime.tex +++ b/doc/halftime.tex @@ -3,7 +3,7 @@ I've written this as an appendix because 1) the aim of the thesis changed drastically from the planning report/proposal 2) partly I'm not sure how to structure my thesis. -My work so far has very much focused on the formalization, i.e. coding. It's +My work so far has very much focused on the formalization, i.e.\ coding. It's unclear to me at this point what I should have in the final report. Here I will describe what I have managed to formalize so far and what outstanding challenges I'm facing. diff --git a/doc/implementation.tex b/doc/implementation.tex index 94198b6..5cb5047 100644 --- a/doc/implementation.tex +++ b/doc/implementation.tex @@ -202,7 +202,7 @@ set. This example illustrates nicely how we can use these combinators to reason about `canonical' types like $\sum$ and $\prod$. Similar combinators can be defined at the other homotopic levels. These combinators are however not applicable in -situations where we want to reason about other types - e.g. types we have +situations where we want to reason about other types - e.g.\ types we have defined ourselves. For instance, after we have proven that all the projections of pre categories are propositions, then we would like to bundle this up to show that the type of pre categories is also a proposition. Formally: @@ -247,7 +247,7 @@ $$ So to give the continuous function $I \to \IsPreCategory$, which is our goal, we introduce $i \tp I$ and proceed by constructing an element of $\IsPreCategory$ by using the fact that all the projections are propositions to generate paths -between all projections. Once we have such a path e.g. $p \tp a.\isIdentity +between all projections. Once we have such a path e.g.\ $p \tp a.\isIdentity \equiv b.\isIdentity$ we can eliminate it with $i$ and thus obtain $p\ i \tp (p\ i).\isIdentity$. This element satisfies exactly that it corresponds to the corresponding projections at either endpoint. Thus the element we construct at @@ -436,7 +436,7 @@ That is, we must demonstrate that there is an isomorphism (on types) between equalities and isomorphisms (on arrows). It is worthwhile to dwell on this for a few seconds. This type looks very similar to univalence for types and is therefore perhaps a bit more intuitive to grasp the implications of. Of course -univalence for types (which is a proposition -- i.e. provable) does not imply +univalence for types (which is a proposition -- i.e.\ provable) does not imply univalence of all pre category since morphisms in a category are not regular functions -- in stead they can be thought of as a generalization hereof. The univalence criterion therefore is simply a way of restricting arrows to behave similarly to maps. @@ -551,7 +551,7 @@ same as the one in the underlying category (they have the same type). Function composition will be reverse function composition from the underlying category. I will refer to things in terms of the underlying category, unless they have an -over-bar. So e.g. $\idToIso$ is a function in the underlying category and the +over-bar. So e.g.\ $\idToIso$ is a function in the underlying category and the corresponding thing is denoted $\wideoverbar{\idToIso}$ in the opposite category. @@ -1333,7 +1333,7 @@ f \rrr (\bind\ g)$ . (\TODO{Better way to typeset $\fish$?}) \subsection{Equivalence of formulations} % The notation I have chosen here in the report -overloads e.g. $\pure$ to both refer to a natural transformation and an arrow. +overloads e.g.\ $\pure$ to both refer to a natural transformation and an arrow. This is of course not a coincidence as the arrow in the Kleisli formulation shall correspond exactly to the map on arrows from the natural transformation called $\pure$. diff --git a/doc/introduction.tex b/doc/introduction.tex index b29d6b5..2441614 100644 --- a/doc/introduction.tex +++ b/doc/introduction.tex @@ -185,16 +185,16 @@ will make it possible to prove more things and to reuse proofs and to try and compare some aspects of this formalization with the existing ones.\TODO{How can I live up to this?} -There are alternative approaches to working in a cubical setting where one can -still have univalence and functional extensionality. One option is to postulate -these as axioms. This approach, however, has other shortcomings, e.g.; you lose - -\nomenindex{canonicity} (\TODO{Pageno!} \cite{huber-2016}). Canonicity means that any -well typed term evaluates to a \emph{canonical} form. For example for a closed -term $e \tp \bN$ it will be the case that $e$ reduces to $n$ applications of -$\mathit{suc}$ to $0$ for some $n$; $e = \mathit{suc}^n\ 0$. Without canonicity -terms in the language can get ``stuck'' -- meaning that they do not reduce to a -canonical form. +There are alternative approaches to working in a cubical setting where +one can still have univalence and functional extensionality. One +option is to postulate these as axioms. This approach, however, has +other shortcomings, e.g. you lose \nomenindex{canonicity} +(\TODO{Pageno!} \cite{huber-2016}). Canonicity means that any well +typed term evaluates to a \emph{canonical} form. For example for a +closed term $e \tp \bN$ it will be the case that $e$ reduces to $n$ +applications of $\mathit{suc}$ to $0$ for some $n$; $e = +\mathit{suc}^n\ 0$. Without canonicity terms in the language can get +``stuck'' -- meaning that they do not reduce to a canonical form. Another approach is to use the \emph{setoid interpretation} of type theory (\cite{hofmann-1995,huber-2016}). With this approach one works diff --git a/doc/presentation.tex b/doc/presentation.tex new file mode 100644 index 0000000..40d345f --- /dev/null +++ b/doc/presentation.tex @@ -0,0 +1,236 @@ +\documentclass[a4paper,handout]{beamer} +\input{packages.tex} +\input{macros.tex} +\title{Univalent Categories} +\author{Frederik Hangh{\o}j Iversen} +\institute{Chalmers University of Technology} +\begin{document} +\frame{\titlepage} + +\begin{frame} + \frametitle{Motivating example} + \framesubtitle{Functional extensionality} +Consider the functions +\begin{align*} + \var{zeroLeft} & \defeq (n \tp \bN) \mto (0 + n \tp \bN) \\ + \var{zeroRight} & \defeq (n \tp \bN) \mto (n + 0 \tp \bN) +\end{align*} +\pause +We have +% +$$ +\prod_{n \tp \bN} n + 0 \equiv 0 + n +$$ +% +\pause +But not +% +$$ +\var{zeroLeft} \equiv \var{zeroRight} +$$ +% +\pause +We need +% +$$ +\funExt \tp \prod_{a \tp A} f\ a \equiv g\ a \to f \equiv g +$$ + +\end{frame} +\begin{frame} + \frametitle{Motivating example} + \framesubtitle{Univalence} + Consider the set + $\{x \mid \phi\ x \land \psi\ x\}$ + \pause + + If we show $\forall x . \psi\ x \equiv \top$ + then we want to conclude + $\{x \mid \phi\ x \land \psi\ x\} \equiv \{x \mid \phi\ x\}$ + \pause + + We need univalence: + $$(A \simeq B) \simeq (A \equiv B)$$ + \pause +% + We will return to $\simeq$, but for not, think of it as an + isomorphism, so it induces maps: + \begin{align*} + \var{toPath} & \tp (A \simeq B) \to (A \equiv B) \\ + \var{toEquiv} & \tp (A \equiv B) \to (A \simeq B) + \end{align*} +\end{frame} +\begin{frame} + \frametitle{Paths} + \framesubtitle{Definition} +Heterogeneous paths +\begin{equation*} + \Path \tp (P \tp I → \MCU) → P\ 0 → P\ 1 → \MCU +\end{equation*} +\pause + For $P \tp I \to \MCU$, $A \tp \MCU$ and $a_0, a_1 \tp A$ + inhabitants of $\Path\ P\ a_0\ a_1$ are like functions +% +$$ +p \tp \prod_{i \tp I} P\ i +$$ +% +Which satisfy $p\ 0 & = a_0$ and $p\ 1 & = a_1$ +\pause + +Homogenous paths +$$ +a_0 \equiv a_1 \defeq \Path\ (\var{const}\ A)\ a_0\ a_1 +$$ +\end{frame} +\begin{frame} +\frametitle{Paths} +\framesubtitle{Functional extenstionality} +$$ +\funExt & \tp \prod_{a \tp A} f\ a \equiv g\ a \to f \equiv g +$$ +\pause +$$ +\funExt\ p \defeq λ i\ a → p\ a\ i +$$ +\pause +$$ +\funExt\ (\var{const}\ \refl) +\tp +\var{zeroLeft} \equiv \var{zeroRight} +$$ +\end{frame} +\begin{frame} + \frametitle{Paths} + \framesubtitle{Homotopy levels} +\begin{align*} +& \isContr && \tp \MCU \to \MCU \\ +& \isContr\ A && \defeq \sum_{c \tp A} \prod_{a \tp A} a \equiv c +\end{align*} +\pause +\begin{align*} +& \isProp && \tp \MCU \to \MCU \\ +& \isProp\ A && \defeq \prod_{a_0, a_1 \tp A} a_0 \equiv a_1 +\end{align*} +\pause +\begin{align*} +& \isSet && \tp \MCU \to \MCU \\ +& \isSet\ A && \defeq \prod_{a_0, a_1 \tp A} \isProp\ (a_0 \equiv a_1) +\end{align*} +\pause +\end{frame} +\begin{frame} +\frametitle{Paths} +\framesubtitle{A few lemmas} +Let $D$ be a type-family: +$$ +D \tp \prod_{b \tp A} \prod_{p \tp a ≡ b} \MCU +$$ +% +\pause +And $d$ and in inhabitant of $D$ at $\refl$: +% +$$ +d \tp D\ a\ \refl +$$ +% +\pause +We then have the function: +% +\begin{equation} +\pathJ\ D\ d \tp \prod_{b \tp A} \prod_{p \tp a ≡ b} D\ a\ p +\end{equation} +\end{frame} +\begin{frame} +\frametitle{Paths} +\framesubtitle{A few lemmas} +Given +\begin{align*} + A & \tp \MCU \\ + P & \tp A \to \MCU \\ + \var{propP} & \tp \prod_{x \tp A} \isProp\ (P\ x) \\ + p & \tp a_0 \equiv a_1 \\ + p_0 & \tp P\ a_0 \\ + p_1 & \tp P\ a_1 +\end{align*} +% +We have +$$ +\lemPropF\ \var{propP}\ p +\tp +\Path\ (\lambda\; i \mto P\ (p\ i))\ p_0\ p_1 +$$ +% +\end{frame} +\begin{frame} +\frametitle{Paths} +\framesubtitle{A few lemmas} +$\prod$ preserves $\isProp$: +$$ +\mathit{propPi} +\tp +\left(\prod_{a \tp A} \isProp\ (P\ a)\right) +\to \isProp\ \left(\prod_{a \tp A} P\ a\right) +$$ +\pause +$\sum$ preserves $\isProp$: +$$ +\mathit{propSig} \tp \isProp\ A \to \left(\prod_{a \tp A} \isProp\ (P\ a)\right) \to \isProp\ \left(\sum_{a \tp A} P\ a\right) +$$ +\end{frame} +\begin{frame} +\frametitle{Categories} +\framesubtitle{Definition} +Data: +\begin{align*} + \Object & \tp \Type \\ + \Arrow & \tp \Object \to \Object \to \Type \\ + \identity & \tp \Arrow\ A\ A \\ + \lll & \tp \Arrow\ B\ C \to \Arrow\ A\ B \to \Arrow\ A\ C +\end{align*} +% +Laws: +% +$$ +h \lll (g \lll f) ≡ (h \lll g) \lll f +$$ +$$ +\identity \lll f ≡ f \x +f \lll \identity ≡ f +$$ +\pause +1-categories: +$$ +\isSet\ (\Arrow\ A\ B) +$$ +\pause +Univalent categories: +$$ +\isEquiv\ (A \equiv B)\ (A \approxeq B)\ \idToIso +$$ +\end{frame} +\begin{frame} +\frametitle{Categories} +\framesubtitle{Univalence} +\begin{align*} +\var{IsIdentity} & \defeq +\prod_{A\ B \tp \Object} \prod_{f \tp \Arrow\ A\ B} \phi\ f +%% \\ +%% & \mathrel{\ } \identity \lll f \equiv f \x f \lll \identity \equiv f +\end{align*} +where +$$ +\phi\ f \defeq \identity \lll f \equiv f \x f \lll \identity \equiv f +$$ +Let $\approxeq$ denote ismorphism of objects. We can then construct +the identity isomorphism in any category: +$$ +\identity , \identity , \var{isIdentity} \tp A \approxeq A +$$ +Likewise since paths are substitutive we can promote a path to an isomorphism: +$$ +\idToIso \tp A ≡ B → A ≊ B +$$ +For a category to be univalent we require this to be an equivalence: +\end{frame} +\end{document} diff --git a/doc/title.tex b/doc/title.tex new file mode 100644 index 0000000..83b90c0 --- /dev/null +++ b/doc/title.tex @@ -0,0 +1,95 @@ +%% FRONTMATTER +\frontmatter +%% \newgeometry{top=3cm, bottom=3cm,left=2.25 cm, right=2.25cm} +\begingroup +\thispagestyle{empty} +{\Huge\thetitle}\\[.5cm] +{\Large A formalization of category theory in Cubical Agda}\\[6cm] +\begin{center} +\includegraphics[width=\linewidth,keepaspectratio]{isomorphism.png} +\end{center} +% Cover text +\vfill +%% \renewcommand{\familydefault}{\sfdefault} \normalfont % Set cover page font +{\Large\theauthor}\\[.5cm] +Master's thesis in Computer Science +\endgroup +%% \end{titlepage} + + +% BACK OF COVER PAGE (BLANK PAGE) +\newpage +%% \newgeometry{a4paper} % Temporarily change margins +%% \restoregeometry +\thispagestyle{empty} +\null + +%% \begin{titlepage} + +% TITLE PAGE +\newpage +\thispagestyle{empty} +\begin{center} + \textsc{\LARGE Master's thesis \the\year}\\[4cm] % Report number is currently not in use + \textbf{\LARGE \thetitle} \\[1cm] + {\large \subtitle}\\[1cm] + {\large \theauthor} + + \vfill + \centering + \includegraphics[width=0.2\pdfpagewidth]{logo_eng.pdf} + \vspace{5mm} + + \textsc{Department of Computer Science and Engineering}\\ + \textsc{{\researchgroup}}\\ + %Name of research group (if applicable)\\ + \textsc{\institution} \\ + \textsc{Gothenburg, Sweden \the\year}\\ +\end{center} + + +% IMPRINT PAGE (BACK OF TITLE PAGE) +\newpage +\thispagestyle{plain} +\textit{\thetitle}\\ +\subtitle\\ +\copyright\ \the\year ~ \textsc{\theauthor} +\vspace{4.5cm} + +\setlength{\parskip}{0.5cm} +\textbf{Author:}\\ +\theauthor\\ +\href{mailto:\authoremail>}{\texttt{<\authoremail>}} + +\textbf{Supervisor:}\\ +\supervisor\\ +\href{mailto:\supervisoremail>}{\texttt{<\supervisoremail>}}\\ +\supervisordepartment + +\textbf{Co-supervisor:}\\ +\cosupervisor\\ +\href{mailto:\cosupervisoremail>}{\texttt{<\cosupervisoremail>}}\\ +\cosupervisordepartment + +\textbf{Examiner:}\\ +\examiner\\ +\href{mailto:\examineremail>}{\texttt{<\examineremail>}}\\ +\examinerdepartment + +\vfill +Master's Thesis \the\year\\ % Report number currently not in use +\department\\ +%Division of Division name\\ +%Name of research group (if applicable)\\ +\institution\\ +SE-412 96 Gothenburg\\ +Telephone +46 31 772 1000 \setlength{\parskip}{0.5cm}\\ +% Caption for cover page figure if used, possibly with reference to further information in the report +%% Cover: Wind visualization constructed in Matlab showing a surface of constant wind speed along with streamlines of the flow. \setlength{\parskip}{0.5cm} +%Printed by [Name of printing company]\\ +Gothenburg, Sweden \the\year + +%% \restoregeometry +%% \end{titlepage} + +\tableofcontents From 4073d70189d5de12ab63612a91edb1d44c0b3269 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frederik=20Hangh=C3=B8j=20Iversen?= Date: Wed, 16 May 2018 11:03:34 +0200 Subject: [PATCH 12/33] Add note about constructive intepretation of univalence --- doc/introduction.tex | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/doc/introduction.tex b/doc/introduction.tex index 2441614..2c41469 100644 --- a/doc/introduction.tex +++ b/doc/introduction.tex @@ -33,7 +33,9 @@ The usual notion of propositional equality in \nomen{Intensional Type motivating examples will highlight this. There exist techniques to circumvent these problems, as we shall see. This thesis will explore an extension to Agda that redefines the notion of propositional -equality and as such is an alternative to these other techniques. +equality and as such is an alternative to these other techniques. What +makes this extension particularly interesting is that it gives a +\emph{constructive} interpretation of univalence. % \section{Motivating examples} % From 1c0b0d9db2b8a21f6fb6f2239fa911c7a006d3d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frederik=20Hangh=C3=B8j=20Iversen?= Date: Wed, 16 May 2018 11:36:26 +0200 Subject: [PATCH 13/33] Small changes --- doc/introduction.tex | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/doc/introduction.tex b/doc/introduction.tex index 2c41469..2ac7baf 100644 --- a/doc/introduction.tex +++ b/doc/introduction.tex @@ -22,20 +22,21 @@ propositional equality at play for a simple example.\TODO{How to For propositional equality the decidability requirement is relaxed. It is not in general possible to decide the correctness of logical -propositions (cf. Hilbert's \nomen{entscheidigungsproblem}). +propositions (cf.\ Hilbert's \emph{entscheidigungsproblem}). Propositional equality are provided by the developer. When introducing definitions this report will use the notation $\defeq$. Judgmental equalities written $=$. For propositional equalities the notation $\equiv$ is used. -The usual notion of propositional equality in \nomen{Intensional Type - Theory} (ITT) is quite restrictive. In the next section a few +The usual notion of propositional equality in \nomenindex{Intensional + Type Theory} (ITT) is quite restrictive. In the next section a few motivating examples will highlight this. There exist techniques to circumvent these problems, as we shall see. This thesis will explore an extension to Agda that redefines the notion of propositional equality and as such is an alternative to these other techniques. What makes this extension particularly interesting is that it gives a -\emph{constructive} interpretation of univalence. +\emph{constructive} interpretation of univalence. What this means will +be elaborated in the following sections. % \section{Motivating examples} % @@ -176,9 +177,9 @@ implementations of category theory in Agda: A formalization in Coq in the homotopic setting: \url{https://github.com/HoTT/HoTT/tree/master/theories/Categories} \item - A formalization in CubicalTT - a language designed for cubical type theory. - Formalizes many different things, but only a few concepts from category - theory: + A formalization in \emph{CubicalTT} -- a language designed for + cubical type theory. Formalizes many different things, but only a + few concepts from category theory: \url{https://github.com/mortberg/cubicaltt} \end{itemize} % @@ -206,7 +207,7 @@ and an equivalence relation $\sim\ \tp X \to X \to \MCU$ on that type. Under the setoid interpretation the equivalence relation serve as a sort of ``local'' propositional equality. Since the developer gets to pick this relation it is not guaranteed to be a congruence relation -apriori. So this must be verified manually by the developer. +a priori. So this must be verified manually by the developer. Furthermore, functions between different setoids must be shown to be setoid homomorphism, that is; they preserve the relation. From 2fce9630721b1c9c7d0bf582184cf9d8a605a633 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frederik=20Hangh=C3=B8j=20Iversen?= Date: Fri, 18 May 2018 13:14:41 +0200 Subject: [PATCH 14/33] TENTATIVE COMMIT --- doc/cubical.tex | 14 +- doc/implementation.tex | 170 ++++---- doc/macros.tex | 27 +- doc/main.tex | 10 +- doc/packages.tex | 28 +- doc/presentation.tex | 773 ++++++++++++++++++++++++++-------- src/Cat/Category.agda | 9 +- src/Cat/Category/Product.agda | 1 - 8 files changed, 748 insertions(+), 284 deletions(-) diff --git a/doc/cubical.tex b/doc/cubical.tex index 6e07ac9..a4a4c5f 100644 --- a/doc/cubical.tex +++ b/doc/cubical.tex @@ -11,8 +11,8 @@ normal definition of judgmental equality is an inductive data type. Cubical Agda discards this type in favor of a new primitives that has certain computational properties exclusive to it. -Exceprts of the source code relevant to this section can be found in appendix -\S\ref{sec:app-cubical}. +The source code can be browsed online and is linked in the beginning +of \S\ref{ch:implementation}. \subsection{The equality type} The usual notion of judgmental equality says that given a type $A \tp \MCU$ and @@ -137,11 +137,13 @@ With this we can now prove the desired equality $f \equiv g$ from section % \begin{align*} p & \tp f \equiv g \\ - p & \defeq \funExt\ \lambda n \to \refl + p & \defeq \funExt\ \phi \end{align*} % -Paths have some other important properties, but they are not the focus of -this thesis. \TODO{Refer the reader somewhere for more info.} +Here $\phi \tp \prod_{n \tp \bN} \var{zeroLeft}\ n \equiv +\var{zeroRight} n$. Paths have some other important properties, but +they are not the focus of this thesis. \TODO{Refer the reader + somewhere for more info.} % \section{Homotopy levels} In ITT all equality proofs are identical (in a closed context). This means that, @@ -273,7 +275,7 @@ $$ We have the function: % \begin{equation} -\pathJ\ D\ d \tp \prod_{b \tp A} \prod_{p \tp a ≡ b} D\ a\ p +\pathJ\ D\ d \tp \prod_{b \tp A} \prod_{p \tp a ≡ b} D\ b\ p \end{equation} % A simple application of $\pathJ$ is for proving that $\var{sym}$ is an diff --git a/doc/implementation.tex b/doc/implementation.tex index 5cb5047..4f06067 100644 --- a/doc/implementation.tex +++ b/doc/implementation.tex @@ -1,12 +1,27 @@ \chapter{Category Theory} \label{ch:implementation} +This implementaiton, including this report, is available as open +source software at: +% +\begin{center} + \gitlink +\end{center} +% +All modules imported for this formalization can be browsed at this +link\footnote{% + In case the linked sources are unavailable the html + documentation can be generated by navigating to the root directory + of the project and executing \texttt{make html}.% +}: +% +\begin{center} +\doclink +\end{center} This implementation formalizes the following concepts: % -\newcommand{\sourcebasepath}{http://web.student.chalmers.se/~hanghj/cat/doc/html/} -\newcommand{\sourcelink}[1]{\href{\sourcebasepath#1.html}{\texttt{#1}}} \begin{center} \begin{tabular}{ l l } -Name & Link \\ +Name & Module \\ \hline Equivalences & \sourcelink{Cat.Equivalence} \\ Categories & \sourcelink{Cat.Category} \\ @@ -30,7 +45,7 @@ Furthermore the following items have been partly formalized: % \begin{center} \begin{tabular}{ l l } -Name & Link \\ +Name & Module \\ \hline Category of categories & \sourcelink{Cat.Categories.Cat} \\ Category of relations & \sourcelink{Cat.Categories.Rel} \\ @@ -40,7 +55,7 @@ Monoids & \sourcelink{Cat.Category.Monoid} \\ \end{tabular} \end{center} % -As well as a range of various results about these. E.g. I have shown +As well as a range of various results about these. E.g.\ I have shown that the category of sets has products. In the following I aim to demonstrate some of the techniques employed in this formalization and in the interest of brevity I will not detail all the things I have @@ -64,15 +79,10 @@ where one can reason about two categories by simply focusing on the data. This is achieved by creating a function embodying the ``equality principle'' for a given type. -For the rest of this chapter I will present some of these results. For didactic -reasons no source-code has been included in this chapter. To see the formal -definitions excerpts of the implementation have been included in appendix -\S\ref{ch:app-sources}: -Appendix -\S\ref{sec:app-categories} corresponds to section \S\ref{sec:categories}, -appendix \S\ref{sec:app-products} to section \S\ref{sec:products} -and appendix \S\ref{sec:app-monads} to section \S\ref{sec:monads}. - +For the rest of this chapter I will present some of these results. For +didactic reasons no source-code has been included in this chapter. To +see the formal definitions the reader is referred to the +implementation which is linked in \S\ref{ch:implementation}. \section{Categories} \label{sec:categories} @@ -191,7 +201,7 @@ So the proof goes like this: We `eliminate' the 3 function abstractions by applying $\propPi$ three times. So our proof obligation becomes: % $$ -\isProp \left( \id \comp f \equiv f \x f \comp \id \equiv f \right) +\isProp\ \left( \id \comp f \equiv f \x f \comp \id \equiv f \right) $$ % Then we eliminate the (non-dependent) sigma-type by applying $\propSig$ giving @@ -224,19 +234,21 @@ Each corresponding to the first three laws for categories. Note that since $\IsPreCategory$ is not formulated with a chain of sigma-types we wont have any combinators available to help us here. In stead the paths must be used directly. -\ref{eq:propIsPreCategory} is judgmentally the same as +\ref{eq:propIsPreCategory} is judgmentally the same as: % $$ \prod_{a\ b \tp \IsPreCategory} a \equiv b $$ % -So let $a\ b \tp \IsPreCategory$ be given. To prove the equality $a \equiv b$ is -to give a continuous path from the index-type into the path-space. I.e. a -function $I \to \IsPreCategory$. This path must satisfy being being judgmentally -the same as $a$ at the left endpoint and $b$ at the right endpoint. We know we -can form a continuous path between all projections of $a$ and $b$, this follows -from the type of all the projections being mere propositions. For instance, the -path between $a.\isIdentity$ and $b.\isIdentity$ is simply formed by: +So to prove the proposition let $a\ b \tp \IsPreCategory$ be given. To +prove the equality $a \equiv b$ is to give a continuous path from the +index-type into the path-space. I.e.\ a function $I \to +\IsPreCategory$. This path must satisfy being being judgmentally the +same as $a$ at the left endpoint and $b$ at the right endpoint. We +know we can form a continuous path between all projections of $a$ and +$b$, this follows from the type of all the projections being mere +propositions. For instance, the path between $a.\isIdentity$ and +$b.\isIdentity$ is simply formed by: % $$ \propIsIdentity\ a.\isIdentity\ b.\isIdentity @@ -270,18 +282,19 @@ theory, namely that you have to wrap and unwrap equalities at different levels. It is worth noting that proving this theorem with the regular inductive equality type would already not be possible, since we at least need extensionality (the projections are all $\prod$-types). Assuming we had functional extensionality -available to us as an axiom, we would use functional extensionality (in -reverse?) to retrieve the equalities in $a$ and $b$, pattern-match on them to +available to us as an axiom, we would use functional extensionality \TODO{in +reverse?} to retrieve the equalities in $a$ and $b$, pattern-match on them to see that they are both $\refl$ and then close the proof with $\refl$. Of course this theorem is not so interesting in the setting of ITT since we know a priori that equality proofs are unique. -The situation is a bit more complicated when we have a dependent type. For -instance, when we want to show that $\IsCategory$ is a mere proposition. -$\IsCategory$ is a record with two fields, a witness to being a pre category and -the univalence condition. Recall that the univalence condition is indexed by the -identity-proof. So to follow the same recipe as above, let $a\ b \tp -\IsCategory$ be given, to show them equal, we now need to give two paths. One homogeneous: +The situation is a bit more complicated when we have a dependent type. +For instance, when we want to show that $\IsCategory$ is a mere +proposition. The type $\IsCategory$ is a record with two fields, a +witness to being a pre category and the univalence condition. Recall +that the univalence condition is indexed by the identity-proof. So to +follow the same recipe as above, let $a\ b \tp \IsCategory$ be given, +to show them equal, we now need to give two paths. One homogeneous: % $$ p \tp a.\isPreCategory \equiv b.\isPreCategory @@ -340,7 +353,7 @@ The usual notion of a function $f \tp A \to B$ having an inverses is: % \begin{equation} \label{eq:isomorphism} -\sum_{g \tp B \to A} f \comp g \equiv \identity_{B} \x g \comp f \equiv \identity_{A} +\sum_{g \tp B \to A} f \comp g \equiv \identity \x g \comp f \equiv \identity \end{equation} % This is defined in \cite[p. 129]{hott-2013} where it is referred to as the a @@ -384,9 +397,10 @@ I give its definition here mainly for completeness, because as I stated we can move away from this specific instantiation and think about it more abstractly once we have shown that this definition actually works as an equivalence. -$\var{fromIso}$ can be found in \cite{cubical-agda} where it is known as -$\var{gradLemma}$. The implementation of $\var{fromIso}$ as well as the proof -that this equivalence is a proposition (\ref{eq:propIsEquiv}) can be found in my +The implementation of $\var{fromIso}$ can be found in +\cite{cubical-agda} where it is known as $\var{gradLemma}$. The +implementation of $\var{fromIso}$ as well as the proof that this +equivalence is a proposition (\ref{eq:propIsEquiv}) can be found in my implementation. We say that two types $A\;B \tp \Type$ are equivalent exactly if there exists an @@ -586,27 +600,27 @@ go between $\wideoverbar{\approxeq}$ and $\approxeq$. An inhabitant of $A \approxeq B$ is simply an arrow $f \tp \Arrow\ A\ B$ and its inverse $g \tp \Arrow\ B\ A$. In the opposite category $g$ will play the role of the isomorphism and $f$ will be the inverse. Similarly we can -go in the opposite direction. I name these maps $\shuffle \tp (A \approxeq +go in the opposite direction. I name these maps $\shufflef \tp (A \approxeq B) \to (A \wideoverbar{\approxeq} B)$ and $\shuffle^{-1} \tp (A \wideoverbar{\approxeq} B) \to (A \approxeq B)$ respectively. As the inverse of $\wideoverbar{\idToIso}$ I will pick $\wideoverbar{\isoToId} -\defeq \isoToId \comp \shuffle$. The proof that they are inverses go as +\defeq \isoToId \comp \shufflef$. The proof that they are inverses go as follows: % \begin{align*} \wideoverbar{\isoToId} \comp \wideoverbar{\idToIso} & = -\isoToId \comp \shuffle \comp \wideoverbar{\idToIso} +\isoToId \comp \shufflef \comp \wideoverbar{\idToIso} \\ %% ≡⟨ cong (λ φ → φ x) (cong (λ φ → η ⊙ shuffle ⊙ φ) (funExt lem)) ⟩ \\ % & \equiv -\isoToId \comp \shuffle \comp \inv{\shuffle} \comp \idToIso +\isoToId \comp \shufflef \comp \inv{\shufflef} \comp \idToIso && \text{lemma} \\ %% ≡⟨⟩ \\ & \equiv \isoToId \comp \idToIso -&& \text{$\shuffle$ is an isomorphism} \\ +&& \text{$\shufflef$ is an isomorphism} \\ & \equiv \identity && \text{$\isoToId$ is an isomorphism} @@ -615,7 +629,7 @@ follows: The other direction is analogous. The lemma used in step 2 of this proof states that $\wideoverbar{idToIso} \equiv -\inv{\shuffle} \comp \idToIso$. This is a rather straight-forward proof +\inv{\shufflef} \comp \idToIso$. This is a rather straight-forward proof since being-an-inverse-of is a proposition, so it suffices to show that their first components are equal, but this holds judgmentally. @@ -681,7 +695,7 @@ together. Step one will be proven with the following lemma: % \begin{align} \label{eq:equivPropSig} -\left(\prod_{a \tp A} \isProp (P\ a)\right) \to \prod_{x\;y \tp \sum_{a \tp A} P\ a} (x \equiv y) \simeq (\fst\ x \equiv \fst\ y) +\left(\prod_{a \tp A} \isProp\ (P\ a)\right) \to \prod_{x\;y \tp \sum_{a \tp A} P\ a} (x \equiv y) \simeq (\fst\ x \equiv \fst\ y) \end{align} % The lemma states that for pairs whose second component are mere propositions @@ -705,7 +719,7 @@ also be equivalent. For our purposes $P \defeq \isEquiv\ A\ B$ and $Q \defeq \prod_{f \tp A \to B} \left( \isEquiv\ A\ B\ f \simeq \Isomorphism\ f \right) \end{align} -First, lets prove \ref{eq:equivPropSig}: Let $propP \tp \prod_{a \tp A} \isProp (P\ a)$ and $x\;y \tp \sum_{a \tp A} P\ a$ be given. Because +First, lets prove \ref{eq:equivPropSig}: Let $propP \tp \prod_{a \tp A} \isProp\ (P\ a)$ and $x\;y \tp \sum_{a \tp A} P\ a$ be given. Because of $\var{fromIsomorphism}$ it suffices to give an isomorphism between $x \equiv y$ and $\fst\ x \equiv \fst\ y$: % @@ -770,7 +784,7 @@ end, let $X\;Y \tp \Isomorphism\ f$ be given. Name the maps $x\;y \tp B paths: $p \tp x \equiv y$ and $\Path\ (\lambda\; i \to \var{AreInverses}\ f\ (p\ i))\ \mathcal{X}\ \mathcal{Y}$ where $\mathcal{X}$ and $\mathcal{Y}$ denotes the witnesses that $x$ (respectively $y$) is an -inverse to $f$. $p$ is inhabited by: +inverse to $f$. The path $p$ is inhabited by: % \begin{align*} x @@ -844,9 +858,6 @@ that there exists a unique arrow $\pi \tp \Arrow\ X\ (A \x B)$ satisfying $\pi$ is called the product (arrow) of $f$ and $g$. \subsection{Span category} - -\newcommand\pairA{\mathcal{A}} -\newcommand\pairB{\mathcal{B}} Given a base category $\bC$ and two objects in this category $\pairA$ and $\pairB$ we can construct the \nomenindex{span category}: @@ -1018,7 +1029,7 @@ isomorphism, and create a path from this: \begin{align} \label{eq:univ-2} \begin{split} -\var{iso} \tp & X \cong Y \\ +\var{iso} \tp & X \approxeq Y \\ & \Path\ (λ i → \Arrow\ (\widetilde{p}\ i)\ \mathcal{A})\ x_{\mathcal{A}}\ y_{\mathcal{A}} \\ & \Path\ (λ i → \Arrow\ (\widetilde{p}\ i)\ \mathcal{B})\ x_{\mathcal{B}}\ y_{\mathcal{B}} \end{split} @@ -1084,7 +1095,7 @@ To show that this choice fits the bill I must now verify that it satisfies y_{\mathcal{A}} \lll f ≡ x_{\mathcal{A}} × y_{\mathcal{B}} \lll f ≡ x_{\mathcal{B}} \end{align} % -Which, since $f$ is an isomorphism and $p_{\mathcal{A}}$ (resp. $p_{\mathcal{B}}$) +Which, since $f$ is an isomorphism and $p_{\mathcal{A}}$ (resp.\ $p_{\mathcal{B}}$) is a path varying according to a path constructed from this isomorphism, this is exactly what \ref{eq:domain-twist-0} gives us. % @@ -1100,7 +1111,7 @@ This concludes the first direction of the isomorphism that we are constructing. For the other direction we are given the isomorphism: % $$ -(f, \inv{f}, \var{inv}_f) +(f, \inv{f}, \var{inv}_f, \var{inv}_{\inv{f}}) \tp (X, x_{\mathcal{A}}, x_{\mathcal{B}}) \approxeq (Y, y_{\mathcal{A}}, y_{\mathcal{B}}) $$ @@ -1108,7 +1119,10 @@ $$ Projecting out the first component gives us the isomorphism % $$ -(\fst\ f, \fst\ \inv{f}, \congruence\ \fst\ \var{inv}_f, \congruence\ \fst\ \var{inv}_{\inv{f}}) +(\fst\ f, \fst\ \inv{f} +, \congruence\ \fst\ \var{inv}_f +, \congruence\ \fst\ \var{inv}_{\inv{f}} +) \tp X \approxeq Y $$ % @@ -1141,11 +1155,11 @@ This is achieved with the following lemma: % Which is used without proof. See the implementation for the details. -\ref{eq:product-paths} is the proven with the propositions: +\ref{eq:product-paths} is then proven with the propositions: % \begin{align} \begin{split} -\label{eq:product-paths} +%% \label{eq:product-paths} \var{coe}\ \widetilde{p}_{\mathcal{A}}\ x_{\mathcal{A}} ≡ y_{\mathcal{A}}\\ \var{coe}\ \widetilde{p}_{\mathcal{B}}\ x_{\mathcal{B}} ≡ y_{\mathcal{B}} \end{split} @@ -1155,7 +1169,7 @@ The proof of the first one is: % \begin{align*} \var{coe}\ \widetilde{p}_{\mathcal{A}}\ x_{\mathcal{A}} - & ≡ x_{\mathcal{A}} \lll \fst\ \inv{f} && \text{$\var{coeDom}$ and the isomorphism $f, \inv{f}$} \\ + & ≡ x_{\mathcal{A}} \lll \fst\ \inv{f} && \text{\ref{eq:coeDom} and the isomorphism $f, \inv{f}$} \\ & ≡ y_{\mathcal{A}} && \text{\ref{eq:pairArrowLaw} for $\inv{f}$} \end{align*} % @@ -1167,10 +1181,10 @@ gory details. % \subsection{Propositionality of products} % -Now that we have constructed the span category\index{span category} I will - demonstrate how to use this to prove that products are propositional. I will - do this by showing that terminal objects in this category are equivalent to - products: +Now that we have constructed the span category\index{span category} I +will demonstrate how to use this to prove that products are +propositional. I will do this by showing that terminal objects in this +category are equivalent to products: % \begin{align} \var{Terminal} ≃ \var{Product}\ ℂ\ \mathcal{A}\ \mathcal{B} @@ -1179,7 +1193,7 @@ Now that we have constructed the span category\index{span category} I will And as always we do this by constructing an isomorphism: % In the direction $\var{Terminal} → \var{Product}\ ℂ\ \mathcal{A}\ \mathcal{B}$ -we are given a terminal object $X, x_𝒜, x_ℬ$. $X$ Will be the product-object and +we are given a terminal object $X, x_𝒜, x_ℬ$. $X$ will be the product-object and $x_𝒜, x_ℬ$ will be the product arrows, so it just remains to verify that this is indeed a product. That is, for an object $Y$ and two arrows $y_𝒜 \tp \Arrow\ Y\ 𝒜$, $y_ℬ\ \Arrow\ Y\ ℬ$ we must find a unique arrow $f \tp @@ -1265,8 +1279,8 @@ The monoidal formulation of monads consists of the following data: \label{eq:monad-monoidal-data} \begin{split} \EndoR & \tp \Endo ℂ \\ - \pure & \tp \NT{\EndoR^0}{\EndoR} \\ - \join & \tp \NT{\EndoR^2}{\EndoR} + \pureNT & \tp \NT{\EndoR^0}{\EndoR} \\ + \joinNT & \tp \NT{\EndoR^2}{\EndoR} \end{split} \end{align} % @@ -1299,11 +1313,11 @@ The Kleisli-formulation consists of the following data: \begin{align} \begin{split} \label{eq:monad-kleisli-data} -\EndoR & \tp \Object → \Object \\ +\omapR & \tp \Object → \Object \\ \pure & \tp % \prod_{X \tp Object} - \Arrow\ X\ (\EndoR\ X) \\ - \bind & \tp % \prod_{X\;Y \tp Object} → \Arrow\ X\ (\EndoR\ Y) - \Arrow\ (\EndoR\ X)\ (\EndoR\ Y) + \Arrow\ X\ (\omapR\ X) \\ + \bind & \tp % \prod_{X\;Y \tp Object} → \Arrow\ X\ (\omapR\ Y) + \Arrow\ (\omapR\ X)\ (\omapR\ Y) \end{split} \end{align} % @@ -1346,22 +1360,20 @@ In the monoidal formulation we can define $\bind$: \newcommand\pureX{\wideoverbar{\pure}}% \newcommand\fmapX{\wideoverbar{\fmap}}% \begin{align} -\bind\ f \defeq \joinX \lll \fmap\ f +\bind\ f \defeq \join \lll \fmap\ f \end{align} % And likewise in the Kleisli formulation we can define $\join$: % \begin{align} -\join \defeq \bindX\ \identity +\join \defeq \bind\ \identity \end{align} % -Here $\joinX$ corresponds to the arrow from the natural -transformation $\join$. $\bindX$ on the other hand corresponds to a -natural transformation constructed from $\bind$. It now remains to show that -this construction indeed gives rise to a monad. This will be done in two steps. -First we will assume that we have a monad in the monoidal form; $(\EndoR, \pure, -\join)$ and then show that $\EndoR, \pure, \bind$ is indeed a monad in the -Kleisli form. In the second part we will show the other direction. +It now remains to show that this construction indeed gives rise to a +monad. This will be done in two steps. First we will assume that we +have a monad in the monoidal form; $(\EndoR, \pure, \join)$ and then +show that $(\omapR, \pure, \bind)$ is indeed a monad in the Kleisli +form. In the second part we will show the other direction. \subsubsection{Monoidal to Kleisli} Let $(\EndoR, \pure, \join)$ be given as in \ref{eq:monad-monoidal-data} @@ -1376,11 +1388,11 @@ formulation we pick: \end{split} \end{align} % -$\EndoRX$ is the object map of the endo-functor $\EndoR$, -$\pureX$ and $\joinX$ are the arrows from the natural -transformations $\pure$ and $\join$ respectively. $\fmapX$ is the -arrow map of the endo-functor $\EndoR$. It now just remains to verify -the laws \kleislilaws. For \ref{eq:monad-kleisli-laws-0}: +$\EndoRX$ is the object map of the endo-functor $\EndoR$, $\pureX$ and +$\joinX$ are the arrows from the natural transformations $\pure$ and +$\join$ respectively. The term $\fmapX$ is the arrow map of the +endo-functor $\EndoR$. It now just remains to verify the laws +\kleislilaws. For \ref{eq:monad-kleisli-laws-0}: % \begin{align*} \bind\ \pure & ≡ diff --git a/doc/macros.tex b/doc/macros.tex index 0924882..a3939c1 100644 --- a/doc/macros.tex +++ b/doc/macros.tex @@ -72,13 +72,17 @@ \newcommand\isequiv{\varindex{isequiv}} \newcommand\qinv{\varindex{qinv}} \newcommand\fiber{\varindex{fiber}} -\newcommand\shuffle{\varindex{shuffle}} +\newcommand\shufflef{\varindex{shuffle}} \newcommand\Univalent{\varindex{Univalent}} \newcommand\refl{\varindex{refl}} \newcommand\isoToId{\varindex{isoToId}} \newcommand\Isomorphism{\varindex{Isomorphism}} \newcommand\rrr{\ggg} -\newcommand\fish{\mathrel{\wideoverbar{\rrr}}} +%% \newcommand\fish{\mathbin{↣}} +%% \newcommand\fish{\mathbin{⤅}} +\newcommand\fish{\mathbin{⤇}} +%% \newcommand\fish{\mathbin{⤜}} +%% \newcommand\fish{\mathrel{\wideoverbar{\rrr}}} \newcommand\fst{\varindex{fst}} \newcommand\snd{\varindex{snd}} \newcommand\Path{\varindex{Path}} @@ -87,12 +91,29 @@ \newcommand*{\QED}{\hfill\ensuremath{\square}}% \newcommand\uexists{\exists!} \newcommand\Arrow{\varindex{Arrow}} +\newcommand\embellish[1]{\widehat{#1}} +\newcommand\nattrans[1]{\embellish{#1}} +\newcommand\functor[1]{\embellish{#1}} \newcommand\NTsym{\varindex{NT}} \newcommand\NT[2]{\NTsym\ #1\ #2} \newcommand\Endo[1]{\varindex{Endo}\ #1} -\newcommand\EndoR{\mathcal{R}} +\newcommand\EndoR{\functor{\mathcal{R}}} +\newcommand\omapR{\mathcal{R}} \newcommand\funExt{\varindex{funExt}} \newcommand{\suc}[1]{\varindex{suc}\ #1} \newcommand{\trans}{\varindex{trans}} \newcommand{\toKleisli}{\varindex{toKleisli}} \newcommand{\toMonoidal}{\varindex{toMonoidal}} +\newcommand\pairA{\mathcal{A}} +\newcommand\pairB{\mathcal{B}} +\newcommand{\joinNT}{\functor{\varindex{join}}} +\newcommand{\pureNT}{\functor{\varindex{pure}}} +\newcommand{\hrefsymb}[2]{\href{#1}{#2 \ExternalLink}} +\newcommand{\sourcebasepath}{http://web.student.chalmers.se/\textasciitilde hanghj/cat/doc/html/} +\newcommand{\docbasepath}{https://github.com/fredefox/cat/} +\newcommand{\sourcelink}[1]{\hrefsymb + {\sourcebasepath#1.html} + {\texttt{#1}} + } +\newcommand{\gitlink}{\hrefsymb{\docbasepath}{\texttt{\docbasepath}}} +\newcommand{\doclink}{\hrefsymb{\sourcebasepath}{\texttt{\sourcebasepath}}} diff --git a/doc/main.tex b/doc/main.tex index 4d01c3a..26b62de 100644 --- a/doc/main.tex +++ b/doc/main.tex @@ -62,12 +62,12 @@ \nocite{coquand-2013} \bibliography{refs} -\begin{appendices} -\setcounter{page}{1} -\pagenumbering{roman} -\input{sources.tex} +%% \begin{appendices} +%% \setcounter{page}{1} +%% \pagenumbering{roman} +%% \input{sources.tex} %% \input{planning.tex} %% \input{halftime.tex} -\end{appendices} +%% \end{appendices} \printindex \end{document} diff --git a/doc/packages.tex b/doc/packages.tex index 6143bf0..cfe33fc 100644 --- a/doc/packages.tex +++ b/doc/packages.tex @@ -4,14 +4,17 @@ \bibliographystyle{plain} \usepackage{xcolor} +%% \mode{ \usepackage[ %% hidelinks, pdfusetitle, pdfsubject={category theory}, pdfkeywords={type theory, homotopy theory, category theory, agda}] {hyperref} -\definecolor{darkorange}{HTML}{ff8c00} -\hypersetup{allbordercolors={darkorange}} +%% } +%% \definecolor{darkorange}{HTML}{ff8c00} +%% \hypersetup{allbordercolors={darkorange}} +\hypersetup{hidelinks} \usepackage{graphicx} \usepackage{parskip} @@ -116,3 +119,24 @@ \makeatother \usepackage{xspace} +\usepackage{tikz} +\newcommand{\ExternalLink}{% + \tikz[x=1.2ex, y=1.2ex, baseline=-0.05ex]{% + \begin{scope}[x=1ex, y=1ex] + \clip (-0.1,-0.1) + --++ (-0, 1.2) + --++ (0.6, 0) + --++ (0, -0.6) + --++ (0.6, 0) + --++ (0, -1); + \path[draw, + line width = 0.5, + rounded corners=0.5] + (0,0) rectangle (1,1); + \end{scope} + \path[draw, line width = 0.5] (0.5, 0.5) + -- (1, 1); + \path[draw, line width = 0.5] (0.6, 1) + -- (1, 1) -- (1, 0.6); + } + } diff --git a/doc/presentation.tex b/doc/presentation.tex index 40d345f..95f73fd 100644 --- a/doc/presentation.tex +++ b/doc/presentation.tex @@ -1,41 +1,49 @@ \documentclass[a4paper,handout]{beamer} +\beamertemplatenavigationsymbolsempty +%% \usecolortheme[named=seagull]{structure} + \input{packages.tex} \input{macros.tex} -\title{Univalent Categories} -\author{Frederik Hangh{\o}j Iversen} +\title[Univalent Categories]{Univalent Categories\\ \footnotesize A formalization of category theory in Cubical Agda} +\newcommand{\myname}{Frederik Hangh{\o}j Iversen} +\author[\myname]{ + \myname\\ + \footnotesize Supervisors: Thierry Coquand, Andrea Vezzosi\\ + Examiner: Andreas Abel +} \institute{Chalmers University of Technology} + \begin{document} \frame{\titlepage} \begin{frame} \frametitle{Motivating example} \framesubtitle{Functional extensionality} -Consider the functions -\begin{align*} - \var{zeroLeft} & \defeq (n \tp \bN) \mto (0 + n \tp \bN) \\ - \var{zeroRight} & \defeq (n \tp \bN) \mto (n + 0 \tp \bN) -\end{align*} -\pause -We have -% -$$ -\prod_{n \tp \bN} n + 0 \equiv 0 + n -$$ -% -\pause -But not -% -$$ -\var{zeroLeft} \equiv \var{zeroRight} -$$ -% -\pause -We need -% -$$ -\funExt \tp \prod_{a \tp A} f\ a \equiv g\ a \to f \equiv g -$$ - + Consider the functions + \begin{align*} + \var{zeroLeft} & \defeq \lambda (n \tp \bN) \mto (0 + n \tp \bN) \\ + \var{zeroRight} & \defeq \lambda (n \tp \bN) \mto (n + 0 \tp \bN) + \end{align*} + \pause + We have + % + $$ + \prod_{n \tp \bN} \var{zeroLeft}\ n \equiv \var{zeroRight}\ n + $$ + % + \pause + But not + % + $$ + \var{zeroLeft} \equiv \var{zeroRight} + $$ + % + \pause + We need + % + $$ + \funExt \tp \prod_{a \tp A} f\ a \equiv g\ a \to f \equiv g + $$ \end{frame} \begin{frame} \frametitle{Motivating example} @@ -52,8 +60,8 @@ $$ We need univalence: $$(A \simeq B) \simeq (A \equiv B)$$ \pause -% - We will return to $\simeq$, but for not, think of it as an + % + We will return to $\simeq$, but for now think of it as an isomorphism, so it induces maps: \begin{align*} \var{toPath} & \tp (A \simeq B) \to (A \equiv B) \\ @@ -63,174 +71,579 @@ $$ \begin{frame} \frametitle{Paths} \framesubtitle{Definition} -Heterogeneous paths -\begin{equation*} - \Path \tp (P \tp I → \MCU) → P\ 0 → P\ 1 → \MCU -\end{equation*} -\pause + Heterogeneous paths + \begin{equation*} + \Path \tp (P \tp I → \MCU) → P\ 0 → P\ 1 → \MCU + \end{equation*} + \pause For $P \tp I \to \MCU$, $A \tp \MCU$ and $a_0, a_1 \tp A$ inhabitants of $\Path\ P\ a_0\ a_1$ are like functions -% -$$ -p \tp \prod_{i \tp I} P\ i -$$ -% -Which satisfy $p\ 0 & = a_0$ and $p\ 1 & = a_1$ -\pause + % + $$ + p \tp \prod_{i \tp I} P\ i + $$ + % + Which satisfy $p\ 0 & = a_0$ and $p\ 1 & = a_1$ + \pause -Homogenous paths -$$ -a_0 \equiv a_1 \defeq \Path\ (\var{const}\ A)\ a_0\ a_1 -$$ + Homogenous paths + $$ + a_0 \equiv a_1 \defeq \Path\ (\var{const}\ A)\ a_0\ a_1 + $$ \end{frame} \begin{frame} -\frametitle{Paths} -\framesubtitle{Functional extenstionality} -$$ -\funExt & \tp \prod_{a \tp A} f\ a \equiv g\ a \to f \equiv g -$$ -\pause -$$ -\funExt\ p \defeq λ i\ a → p\ a\ i -$$ -\pause -$$ -\funExt\ (\var{const}\ \refl) -\tp -\var{zeroLeft} \equiv \var{zeroRight} -$$ + \frametitle{Paths} + \framesubtitle{Functional extenstionality} + $$ + \funExt & \tp \prod_{a \tp A} f\ a \equiv g\ a \to f \equiv g + $$ + \pause + $$ + \funExt\ p \defeq λ i\ a → p\ a\ i + $$ + \pause + $$ + \funExt\ (\var{const}\ \refl) + \tp + \var{zeroLeft} \equiv \var{zeroRight} + $$ \end{frame} \begin{frame} \frametitle{Paths} \framesubtitle{Homotopy levels} -\begin{align*} -& \isContr && \tp \MCU \to \MCU \\ -& \isContr\ A && \defeq \sum_{c \tp A} \prod_{a \tp A} a \equiv c -\end{align*} -\pause -\begin{align*} -& \isProp && \tp \MCU \to \MCU \\ -& \isProp\ A && \defeq \prod_{a_0, a_1 \tp A} a_0 \equiv a_1 -\end{align*} -\pause -\begin{align*} -& \isSet && \tp \MCU \to \MCU \\ -& \isSet\ A && \defeq \prod_{a_0, a_1 \tp A} \isProp\ (a_0 \equiv a_1) -\end{align*} -\pause + \begin{align*} + & \isContr && \tp \MCU \to \MCU \\ + & \isContr\ A && \defeq \sum_{c \tp A} \prod_{a \tp A} a \equiv c + \end{align*} + \pause + \begin{align*} + & \isProp && \tp \MCU \to \MCU \\ + & \isProp\ A && \defeq \prod_{a_0, a_1 \tp A} a_0 \equiv a_1 + \end{align*} + \pause + \begin{align*} + & \isSet && \tp \MCU \to \MCU \\ + & \isSet\ A && \defeq \prod_{a_0, a_1 \tp A} \isProp\ (a_0 \equiv a_1) + \end{align*} + \begin{align*} + & \isGroupoid && \tp \MCU \to \MCU \\ + & \isGroupoid\ A && \defeq \prod_{a_0, a_1 \tp A} \isSet\ (a_0 \equiv a_1) + \end{align*} \end{frame} \begin{frame} -\frametitle{Paths} -\framesubtitle{A few lemmas} -Let $D$ be a type-family: -$$ -D \tp \prod_{b \tp A} \prod_{p \tp a ≡ b} \MCU -$$ -% -\pause -And $d$ and in inhabitant of $D$ at $\refl$: -% -$$ -d \tp D\ a\ \refl -$$ -% -\pause -We then have the function: -% -\begin{equation} -\pathJ\ D\ d \tp \prod_{b \tp A} \prod_{p \tp a ≡ b} D\ a\ p -\end{equation} + \frametitle{Paths} + \framesubtitle{A few lemmas} + Let $D$ be a type-family: + $$ + D \tp \prod_{b \tp A} \prod_{p \tp a ≡ b} \MCU + $$ + % + \pause + And $d$ and in inhabitant of $D$ at $\refl$: + % + $$ + d \tp D\ a\ \refl + $$ + % + \pause + We then have the function: + % + $$ + \pathJ\ D\ d \tp \prod_{b \tp A} \prod_{p \tp a ≡ b} D\ b\ p + $$ \end{frame} \begin{frame} -\frametitle{Paths} -\framesubtitle{A few lemmas} -Given -\begin{align*} - A & \tp \MCU \\ - P & \tp A \to \MCU \\ - \var{propP} & \tp \prod_{x \tp A} \isProp\ (P\ x) \\ - p & \tp a_0 \equiv a_1 \\ - p_0 & \tp P\ a_0 \\ - p_1 & \tp P\ a_1 -\end{align*} -% -We have -$$ -\lemPropF\ \var{propP}\ p -\tp -\Path\ (\lambda\; i \mto P\ (p\ i))\ p_0\ p_1 -$$ -% + \frametitle{Paths} + \framesubtitle{A few lemmas} + Given + \begin{align*} + A & \tp \MCU \\ + P & \tp A \to \MCU \\ + \var{propP} & \tp \prod_{x \tp A} \isProp\ (P\ x) \\ + p & \tp a_0 \equiv a_1 \\ + p_0 & \tp P\ a_0 \\ + p_1 & \tp P\ a_1 + \end{align*} + % + We have + $$ + \lemPropF\ \var{propP}\ p + \tp + \Path\ (\lambda\; i \mto P\ (p\ i))\ p_0\ p_1 + $$ + % \end{frame} \begin{frame} -\frametitle{Paths} -\framesubtitle{A few lemmas} -$\prod$ preserves $\isProp$: -$$ -\mathit{propPi} -\tp -\left(\prod_{a \tp A} \isProp\ (P\ a)\right) -\to \isProp\ \left(\prod_{a \tp A} P\ a\right) -$$ -\pause -$\sum$ preserves $\isProp$: -$$ -\mathit{propSig} \tp \isProp\ A \to \left(\prod_{a \tp A} \isProp\ (P\ a)\right) \to \isProp\ \left(\sum_{a \tp A} P\ a\right) -$$ + \frametitle{Paths} + \framesubtitle{A few lemmas} + $\prod$ preserves $\isProp$: + $$ + \mathit{propPi} + \tp + \left(\prod_{a \tp A} \isProp\ (P\ a)\right) + \to \isProp\ \left(\prod_{a \tp A} P\ a\right) + $$ + \pause + $\sum$ preserves $\isProp$: + $$ + \mathit{propSig} \tp \isProp\ A \to \left(\prod_{a \tp A} \isProp\ (P\ a)\right) \to \isProp\ \left(\sum_{a \tp A} P\ a\right) + $$ \end{frame} \begin{frame} -\frametitle{Categories} -\framesubtitle{Definition} -Data: -\begin{align*} - \Object & \tp \Type \\ - \Arrow & \tp \Object \to \Object \to \Type \\ - \identity & \tp \Arrow\ A\ A \\ - \lll & \tp \Arrow\ B\ C \to \Arrow\ A\ B \to \Arrow\ A\ C -\end{align*} -% -Laws: -% -$$ -h \lll (g \lll f) ≡ (h \lll g) \lll f -$$ -$$ -\identity \lll f ≡ f \x -f \lll \identity ≡ f -$$ -\pause -1-categories: -$$ -\isSet\ (\Arrow\ A\ B) -$$ -\pause -Univalent categories: -$$ -\isEquiv\ (A \equiv B)\ (A \approxeq B)\ \idToIso -$$ + \frametitle{Pre categories} + \framesubtitle{Definition} + Data: + \begin{align*} + \Object & \tp \Type \\ + \Arrow & \tp \Object \to \Object \to \Type \\ + \identity & \tp \Arrow\ A\ A \\ + \lll & \tp \Arrow\ B\ C \to \Arrow\ A\ B \to \Arrow\ A\ C + \end{align*} + % + \pause + Laws: + % + $$ + h \lll (g \lll f) ≡ (h \lll g) \lll f + $$ + $$ + (\identity \lll f ≡ f) + \x + (f \lll \identity ≡ f) + $$ + \pause + 1-categories: + $$ + \isSet\ (\Arrow\ A\ B) + $$ \end{frame} \begin{frame} -\frametitle{Categories} -\framesubtitle{Univalence} -\begin{align*} -\var{IsIdentity} & \defeq -\prod_{A\ B \tp \Object} \prod_{f \tp \Arrow\ A\ B} \phi\ f -%% \\ -%% & \mathrel{\ } \identity \lll f \equiv f \x f \lll \identity \equiv f -\end{align*} -where -$$ -\phi\ f \defeq \identity \lll f \equiv f \x f \lll \identity \equiv f -$$ -Let $\approxeq$ denote ismorphism of objects. We can then construct -the identity isomorphism in any category: -$$ -\identity , \identity , \var{isIdentity} \tp A \approxeq A -$$ -Likewise since paths are substitutive we can promote a path to an isomorphism: -$$ -\idToIso \tp A ≡ B → A ≊ B -$$ -For a category to be univalent we require this to be an equivalence: + \frametitle{Pre categories} + \framesubtitle{Propositionality} + $$ + \isProp\ \left( (\identity \comp f \equiv f) \x (f \comp \identity \equiv f) \right) + $$ + \pause + \begin{align*} + \isProp\ \IsPreCategory + \end{align*} + \pause + \begin{align*} + \var{isAssociative} & \tp \var{IsAssociative}\\ + \isIdentity & \tp \var{IsIdentity}\\ + \var{arrowsAreSets} & \tp \var{ArrowsAreSets} + \end{align*} + \pause + \begin{align*} + & \var{propIsAssociative} && a.\var{isAssociative}\ + && b.\var{isAssociative} && i \\ + & \propIsIdentity && a.\isIdentity\ + && b.\isIdentity && i \\ + & \var{propArrowsAreSets} && a.\var{arrowsAreSets}\ + && b.\var{arrowsAreSets} && i + \end{align*} +\end{frame} +\begin{frame} + \frametitle{Categories} + \framesubtitle{Univalence} + \begin{align*} + \var{IsIdentity} & \defeq + \prod_{A\ B \tp \Object} \prod_{f \tp \Arrow\ A\ B} \phi\ f + %% \\ + %% & \mathrel{\ } \identity \lll f \equiv f \x f \lll \identity \equiv f + \end{align*} + where + $$ + \phi\ f \defeq \identity \lll f \equiv f \x f \lll \identity \equiv f + $$ + \pause + Let $\approxeq$ denote ismorphism of objects. We can then construct + the identity isomorphism in any category: + $$ + \identity , \identity , \var{isIdentity} \tp A \approxeq A + $$ + \pause + Likewise since paths are substitutive we can promote a path to an isomorphism: + $$ + \idToIso \tp A ≡ B → A ≊ B + $$ + \pause + For a category to be univalent we require this to be an equivalence: + % + $$ + \isEquiv\ (A \equiv B)\ (A \approxeq B)\ \idToIso + $$ + % +\end{frame} +\begin{frame} + \frametitle{Categories} + \framesubtitle{Univalence, cont'd} + $$\isEquiv\ (A \equiv B)\ (A \approxeq B)\ \idToIso$$ + \pause% + $$(A \equiv B) \simeq (A \approxeq B)$$ + \pause% + $$(A \equiv B) \cong (A \approxeq B)$$ + \pause% + Name the above maps: + $$\idToIso \tp A ≡ B → A ≊ B$$ + % + $$\isoToId \tp (A \approxeq B) \to (A \equiv B)$$ +\end{frame} +\begin{frame} + \frametitle{Categories} + \framesubtitle{Propositionality} + $$ + \isProp\ \IsCategory = \prod_{a, b \tp \IsCategory} a \equiv b + $$ + \pause + So, for + $$ + a\ b \tp \IsCategory + $$ + the proof obligation is the pair: + % + \begin{align*} + p & \tp a.\isPreCategory \equiv b.\isPreCategory \\ + & \mathrel{\ } \Path\ (\lambda\; i \to (p\ i).Univalent)\ a.\isPreCategory\ b.\isPreCategory + \end{align*} +\end{frame} +\begin{frame} + \frametitle{Categories} + \framesubtitle{Propositionality, cont'd} + First path given by: + $$ + p + \defeq + \var{propIsPreCategory}\ a\ b + \tp + a.\isPreCategory \equiv b.\isPreCategory + $$ + \pause + Use $\lemPropF$ for the latter. + \pause + % + Univalence is indexed by an identity proof. So $A \defeq + IsIdentity\ identity$ and $B \defeq \var{Univalent}$. + \pause + % + $$ + \lemPropF\ \var{propUnivalent}\ p + $$ +\end{frame} + +\begin{frame} + \frametitle{Categories} + \framesubtitle{A theorem} + % + Let the isomorphism $(ι, \inv{ι}) \tp A \approxeq B$. + % + \pause + % + The isomorphism induces the path + % + $$ + p \defeq \idToIso\ (\iota, \inv{\iota}) \tp A \equiv B + $$ + % + \pause + and consequently an arrow: + % + $$ + p_{\var{dom}} \defeq \congruence\ (λ x → \Arrow\ x\ X)\ p + \tp + \Arrow\ A\ X \equiv \Arrow\ B\ X + $$ + % + \pause + The proposition is: + % + \begin{align} + \label{eq:coeDom} + \tag{$\var{coeDom}$} + \prod_{f \tp A \to X} + \var{coe}\ p_{\var{dom}}\ f \equiv f \lll \inv{\iota} + \end{align} +\end{frame} +\begin{frame} + \frametitle{Categories} + \framesubtitle{A theorem, proof} + \begin{align*} + \var{coe}\ p_{\var{dom}}\ f + & \equiv f \lll \inv{(\idToIso\ p)} && \text{By path-induction} \\ + & \equiv f \lll \inv{\iota} + && \text{$\idToIso$ and $\isoToId$ are inverses}\\ + \end{align*} + \pause + % + Induction will be based at $A$. Let $\widetilde{B}$ and $\widetilde{p} + \tp A \equiv \widetilde{B}$ be given. + % + \pause + % + Define the family: + % + $$ + D\ \widetilde{B}\ \widetilde{p} \defeq + \var{coe}\ \widetilde{p}_{\var{dom}}\ f + \equiv + f \lll \inv{(\idToIso\ \widetilde{p})} + $$ + \pause + % + The base-case becomes: + $$ + d \tp D\ A\ \refl = + \var{coe}\ \refl_{\var{dom}}\ f \equiv f \lll \inv{(\idToIso\ \refl)} + $$ +\end{frame} +\begin{frame} + \frametitle{Categories} + \framesubtitle{A theorem, proof, cont'd} + $$ + d \tp + \var{coe}\ \refl_{\var{dom}}\ f \equiv f \lll \inv{(\idToIso\ \refl)} + $$ + \pause + \begin{align*} + \var{coe}\ \refl^*\ f + & \equiv f + && \text{$\refl$ is a neutral element for $\var{coe}$}\\ + & \equiv f \lll \identity \\ + & \equiv f \lll \var{subst}\ \refl\ \identity + && \text{$\refl$ is a neutral element for $\var{subst}$}\\ + & \equiv f \lll \inv{(\idToIso\ \refl)} + && \text{By definition of $\idToIso$}\\ + \end{align*} + \pause + In conclusion, the theorem is inhabited by: + $$ + \label{eq:pathJ-example} + \pathJ\ D\ d\ B\ p + $$ +\end{frame} +\begin{frame} + \frametitle{Span category} \framesubtitle{Definition} Given a base + category $\bC$ and two objects in this category $\pairA$ and $\pairB$ + we can construct the \nomenindex{span category}: + % + \pause + Objects: + $$ + \sum_{X \tp Object} \Arrow\ X\ \pairA × \Arrow\ X\ \pairB + $$ + \pause + % + Arrows between objects $A ,\ a_{\pairA} ,\ a_{\pairB}$ and + $B ,\ b_{\pairA} ,\ b_{\pairB}$: + % + $$ + \sum_{f \tp \Arrow\ A\ B} + b_{\pairA} \lll f \equiv a_{\pairA} \x + b_{\pairB} \lll f \equiv a_{\pairB} + $$ +\end{frame} +\begin{frame} + \frametitle{Span category} + \framesubtitle{Univalence} + \begin{align*} + \label{eq:univ-0} + (X , x_{\mathcal{A}} , x_{\mathcal{B}}) ≡ (Y , y_{\mathcal{A}} , y_{\mathcal{B}}) + \end{align*} + \begin{align*} + \label{eq:univ-1} + \begin{split} + p \tp & X \equiv Y \\ + & \Path\ (λ i → \Arrow\ (p\ i)\ \mathcal{A})\ x_{\mathcal{A}}\ y_{\mathcal{A}} \\ + & \Path\ (λ i → \Arrow\ (p\ i)\ \mathcal{B})\ x_{\mathcal{B}}\ y_{\mathcal{B}} + \end{split} + \end{align*} + \begin{align*} + \begin{split} + \var{iso} \tp & X \approxeq Y \\ + & \Path\ (λ i → \Arrow\ (\widetilde{p}\ i)\ \mathcal{A})\ x_{\mathcal{A}}\ y_{\mathcal{A}} \\ + & \Path\ (λ i → \Arrow\ (\widetilde{p}\ i)\ \mathcal{B})\ x_{\mathcal{B}}\ y_{\mathcal{B}} + \end{split} + \end{align*} + \begin{align*} + (X , x_{\mathcal{A}} , x_{\mathcal{B}}) ≊ (Y , y_{\mathcal{A}} , y_{\mathcal{B}}) + \end{align*} +\end{frame} +\begin{frame} + \frametitle{Span category} + \framesubtitle{Univalence, proof} + % + \begin{align*} + %% (f, \inv{f}, \var{inv}_f, \var{inv}_{\inv{f}}) + %% \tp + (X, x_{\mathcal{A}}, x_{\mathcal{B}}) \approxeq (Y, y_{\mathcal{A}}, y_{\mathcal{B}}) + \to + \begin{split} + \var{iso} \tp & X \approxeq Y \\ + & \Path\ (λ i → \Arrow\ (\widetilde{p}\ i)\ \mathcal{A})\ x_{\mathcal{A}}\ y_{\mathcal{A}} \\ + & \Path\ (λ i → \Arrow\ (\widetilde{p}\ i)\ \mathcal{B})\ x_{\mathcal{B}}\ y_{\mathcal{B}} + \end{split} + \end{align*} + \pause + % + Let $(f, \inv{f}, \var{inv}_f, \var{inv}_{\inv{f}})$ be an inhabitant + of the antecedent.\pause + + Projecting out the first component gives us the isomorphism + % + $$ + (\fst\ f, \fst\ \inv{f} + , \congruence\ \fst\ \var{inv}_f + , \congruence\ \fst\ \var{inv}_{\inv{f}} + ) + \tp X \approxeq Y + $$ + \pause + % + This gives rise to the following paths: + % + \begin{align*} + \begin{split} + \widetilde{p} & \tp X \equiv Y \\ + \widetilde{p}_{\mathcal{A}} & \tp \Arrow\ X\ \mathcal{A} \equiv \Arrow\ Y\ \mathcal{A} \\ + \end{split} + \end{align*} + % +\end{frame} +\begin{frame} + \frametitle{Span category} + \framesubtitle{Univalence, proof, cont'd} + It remains to construct: + % + \begin{align*} + \begin{split} + \label{eq:product-paths} + & \Path\ (λ i → \widetilde{p}_{\mathcal{A}}\ i)\ x_{\mathcal{A}}\ y_{\mathcal{A}} + \end{split} + \end{align*} + \pause + % + This is achieved with the following lemma: + % + \begin{align*} + \prod_{q \tp A \equiv B} \var{coe}\ q\ x_{\mathcal{A}} ≡ y_{\mathcal{A}} + → + \Path\ (λ i → q\ i)\ x_{\mathcal{A}}\ y_{\mathcal{A}} + \end{align*} + % + Which is used without proof.\pause + + So the construction reduces to: + % + \begin{align*} + \var{coe}\ \widetilde{p}_{\mathcal{A}}\ x_{\mathcal{A}} ≡ y_{\mathcal{A}} + \end{align*}% + \pause% + This is proven with: + % + \begin{align*} + \var{coe}\ \widetilde{p}_{\mathcal{A}}\ x_{\mathcal{A}} + & ≡ x_{\mathcal{A}} \lll \fst\ \inv{f} && \text{\ref{eq:coeDom}} \\ + & ≡ y_{\mathcal{A}} && \text{Property of span category} + \end{align*} +\end{frame} +\begin{frame} + \frametitle{Propositionality of products} + We have + % + $$ + \isProp\ \var{Terminal} + $$\pause + % + We can show: + \begin{align*} + \var{Terminal} ≃ \var{Product}\ ℂ\ \mathcal{A}\ \mathcal{B} + \end{align*} + \pause + And since equivalences preserve homotopy levels we get: + % + $$ + \isProp\ \left(\var{Product}\ \bC\ \mathcal{A}\ \mathcal{B}\right) + $$ +\end{frame} +\begin{frame} + \frametitle{Monads} + \framesubtitle{Monoidal form} + % + \begin{align*} + \EndoR & \tp \Endo ℂ \\ + \pureNT + & \tp \NT{\EndoR^0}{\EndoR} \\ + \joinNT + & \tp \NT{\EndoR^2}{\EndoR} + \end{align*} + \pause + % + Let $\fmap$ be the map on arrows of $\EndoR$. Likewise + $\pure$ and $\join$ are the maps of the natural transformations + $\pureNT$ and $\joinNT$ respectively. + % + \begin{align*} + \join \lll \fmap\ \join + & ≡ \join \lll \join \\ + \join \lll \pure\ & ≡ \identity \\ + \join \lll \fmap\ \pure & ≡ \identity + \end{align*} +\end{frame} +\begin{frame} + \frametitle{Monads} + \framesubtitle{Kleisli form} + % + \begin{align*} + \omapR & \tp \Object → \Object \\ + \pure & \tp % \prod_{X \tp Object} + \Arrow\ X\ (\omapR\ X) \\ + \bind & \tp + \Arrow\ X\ (\omapR\ Y) + \to + \Arrow\ (\omapR\ X)\ (\omapR\ Y) + \end{align*}\pause + % + \begin{align*} + \fish & \tp + \Arrow\ A\ (\omapR\ B) + → + \Arrow\ B\ (\omapR\ C) + → + \Arrow\ A\ (\omapR\ C) \\ + f \fish g & \defeq f \rrr (\bind\ g) + \end{align*} + \pause + % + \begin{align*} + \label{eq:monad-kleisli-laws-0} + \bind\ \pure & ≡ \identity_{\omapR\ X} \\ + \label{eq:monad-kleisli-laws-1} + \pure \fish f & ≡ f \\ + \label{eq:monad-kleisli-laws-2} + (\bind\ f) \rrr (\bind\ g) & ≡ \bind\ (f \fish g) + \end{align*} +\end{frame} +\begin{frame} + \frametitle{Monads} + \framesubtitle{Equivalence} + In the monoidal formulation we can define $\bind$: + % + $$ + \bind\ f \defeq \join \lll \fmap\ f + $$ + \pause + % + And likewise in the Kleisli formulation we can define $\join$: + % + $$ + \join \defeq \bind\ \identity + $$ + \pause + The laws are logically equivalent. So we get: + % + $$ + \var{Monoidal} \simeq \var{Kleisli} + $$ + % \end{frame} \end{document} diff --git a/src/Cat/Category.agda b/src/Cat/Category.agda index c6e624a..8d9bdb8 100644 --- a/src/Cat/Category.agda +++ b/src/Cat/Category.agda @@ -55,14 +55,7 @@ record RawCategory (ℓa ℓb : Level) : Set (lsuc (ℓa ⊔ ℓb)) where -- infixl 8 _>>>_ 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 - + -- | Reverse arrow composition _>>>_ : {A B C : Object} → (Arrow A B) → (Arrow B C) → Arrow A C f >>> g = g <<< f diff --git a/src/Cat/Category/Product.agda b/src/Cat/Category/Product.agda index 418ec22..3b8bd16 100644 --- a/src/Cat/Category/Product.agda +++ b/src/Cat/Category/Product.agda @@ -1,7 +1,6 @@ {-# OPTIONS --cubical --caching #-} module Cat.Category.Product where - open import Cat.Prelude as P hiding (_×_ ; fst ; snd) open import Cat.Equivalence From 01159930de23366f23a2488f61e8a690377982d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frederik=20Hangh=C3=B8j=20Iversen?= Date: Tue, 22 May 2018 13:45:52 +0200 Subject: [PATCH 15/33] Add section on functors and natural transformations Also do not use ugly overbar --- doc/implementation.tex | 228 ++++++++++++++++++++++++++---------- doc/macros.tex | 11 +- doc/packages.tex | 1 + src/Cat/Category/Monad.agda | 3 +- 4 files changed, 176 insertions(+), 67 deletions(-) diff --git a/doc/implementation.tex b/doc/implementation.tex index 4f06067..0a26bd0 100644 --- a/doc/implementation.tex +++ b/doc/implementation.tex @@ -1261,6 +1261,55 @@ That in any category: \prod_{A\ B \tp \Object} \isProp\ (\var{Product}\ \bC\ A\ B) \end{align} % +\section{Functors and natural transformations} +For the sake of completeness I will mention the definition of functors +and natural transformations. Please refer to the implementation for +the full details. +% +\subsection{Functors} +Given two categories $\bC$ and $\bD$ a functor consists of the +following data: +% +\begin{align*} + \omapF & \tp ℂ.\Object → 𝔻.\Object \\ + \fmap & \tp ℂ.\Arrow\ A\ B → 𝔻.\Arrow\ (\omapF\ A)\ (\omapF\ B) +\end{align*} +% +And the following laws: +\begin{align*} +\fmap\ ℂ.\identity & ≡ 𝔻.identity \\ +\fmap\ (g \clll f) & ≡ \fmap\ g \dlll \fmap\ f +\end{align*} +% +The implementation can be found here: +% +\begin{center} +\sourcelink{Cat.Category.Functor} +\end{center} +\subsection{Natural Transformation} +Given two functors between categories $\bC$ and $\bD$. Name them +$\FunF$ and $\FunG$. A natural transformation is a family of arrows: +% +\begin{align*} +\prod_{C \tp ℂ.\Object} \bD.\Arrow\ (\omapF\ C)\ (\omapG\ C) +\end{align*} +% +This family of arrows can be seen as the data. If $\theta$ is a +natural transformation $\theta\ C$ will be called the component (of +$\theta$) at $C$. The laws of this family of morphism is the +naturality condition: +% +\begin{align*} +\prod_{f \tp ℂ.\Arrow\ A\ B} + (θ\ B) \dlll (\FunF.\fmap\ f) ≡ (\FunG.\fmap\ f) \dlll (θ\ A) +\end{align*} +% +The implementation can be found here: +% +\begin{center} +\sourcelink{Cat.Category.NaturalTransformation} +\end{center} + \section{Monads} \label{sec:monads} In this section I present two formulations of monads. The two representations @@ -1269,8 +1318,14 @@ simply monoidal monads and Kleisli monads for short. We then show that the two formulations are equivalent, which due to univalence gives us a path between the two types. -Let a category $\bC$ be given. In the remainder of this sections all objects and -arrows will implicitly refer to objects and arrows in this category. +Let a category $\bC$ be given. In the remainder of this sections all +objects and arrows will implicitly refer to objects and arrows in this +category. I will also use the notation $\EndoR$ to refer to an +endofunctor on this category. Its map on objects will be denoted +$\omapR$ and its map on arrows will be denoted $\fmap$. Likewise I +will use the notation $\pureNT$ to refer to a natural transformation +and its component at a given (implicit) object will be denoted +$\pure$. % \subsection{Monoidal formulation} The monoidal formulation of monads consists of the following data: @@ -1278,7 +1333,7 @@ The monoidal formulation of monads consists of the following data: \begin{align} \label{eq:monad-monoidal-data} \begin{split} - \EndoR & \tp \Endo ℂ \\ + \EndoR & \tp \Functor\ ℂ\ \bC \\ \pureNT & \tp \NT{\EndoR^0}{\EndoR} \\ \joinNT & \tp \NT{\EndoR^2}{\EndoR} \end{split} @@ -1321,8 +1376,15 @@ The Kleisli-formulation consists of the following data: \end{split} \end{align} % -The objects $X$ and $Y$ are implicitly universally quantified. - +The objects $X$ and $Y$ are implicitly universally quantified. With this data we can construct the \nomenindex{Kleisli arrow}: +% +\begin{align*} +\fish & \tp \Arrow\ A\ (\omapR\ B) + \to \Arrow\ B\ (\omapR\ C) + \to \Arrow\ A\ (\omapR\ C) \\ +f \fish g & \defeq f \rrr (\bind\ g) +\end{align*} +% It is interesting to note here that this formulation does not talk about natural transformations or other such constructs from category theory. All we have here is a regular maps on objects and a pair of arrows. @@ -1339,11 +1401,10 @@ This data must satisfy: \end{align} \newcommand\kleislilaws{\ref{eq:monad-kleisli-laws-0}, \ref{eq:monad-kleisli-laws-1} and \ref{eq:monad-kleisli-laws-2}}% % -Here likewise the arrows $f \tp \Arrow\ X\ (\EndoR\ Y)$ and $g \tp -\Arrow\ Y\ (\EndoR\ Z)$ are universally quantified (as well as the objects they -range over). $\fish$ is the Kleisli-arrow which is defined as $f \fish g \defeq -f \rrr (\bind\ g)$ . (\TODO{Better way to typeset $\fish$?}) - +Here likewise the arrows $f \tp \Arrow\ X\ (\omapR\ Y)$ and $g \tp +\Arrow\ Y\ (\omapR\ Z)$ are universally quantified as well as the +objects they range over. +% \subsection{Equivalence of formulations} % The notation I have chosen here in the report @@ -1376,27 +1437,27 @@ show that $(\omapR, \pure, \bind)$ is indeed a monad in the Kleisli form. In the second part we will show the other direction. \subsubsection{Monoidal to Kleisli} -Let $(\EndoR, \pure, \join)$ be given as in \ref{eq:monad-monoidal-data} +Let $(\EndoR, \pureNT, \joinNT)$ be given as in \ref{eq:monad-monoidal-data} satisfying the laws \monoidallaws. For the data of the Kleisli formulation we pick: % \begin{align} \begin{split} - \EndoR & \defeq \EndoRX \\ - \pure & \defeq \pureX \\ - \bind\ f & \tp \joinX \lll \fmapX\ f + \omapR & \defeq \omapR \\ + \pure & \defeq \pure \\ + \bind\ f & \defeq \join \lll \fmap\ f \end{split} \end{align} % -$\EndoRX$ is the object map of the endo-functor $\EndoR$, $\pureX$ and -$\joinX$ are the arrows from the natural transformations $\pure$ and -$\join$ respectively. The term $\fmapX$ is the arrow map of the -endo-functor $\EndoR$. It now just remains to verify the laws +Again $\omapR$ is the object map of the endo-functor $\EndoR$, $\pure$ +and $\join$ are the arrows from the natural transformations $\pureNT$ +and $\joinNT$ respectively and $\fmap$ is the map on arrows of the +endofunctor $\EndoR$. It now just remains to verify the laws \kleislilaws. For \ref{eq:monad-kleisli-laws-0}: % \begin{align*} -\bind\ \pure & ≡ -\join \lll (\fmap\ \pure) && \text{By definition} \\ +\bind\ \pure & = +\join \lll (\fmap\ \pure) \\ & ≡ \identity && \text{By \ref{eq:monad-monoidal-laws-2}} \end{align*} % @@ -1404,57 +1465,89 @@ For \ref{eq:monad-kleisli-laws-1}: % \begin{align*} \pure \fish f -& \equiv %%% -\pure \ggg \bind\ f && \text{By definition} \\ & ≡ -\bind\ f \lll \pure && \text{By definition} \\ & ≡ -\joinX \lll \fmapX\ f \lll \pureX && \text{By definition} \\ & ≡ -\joinX \lll \pureX \lll f && \text{$\pure$ is a natural transformation} \\ & ≡ +& = %%% +\pure \ggg \bind\ f \\ & = +\bind\ f \lll \pure \\ & = +\join \lll \fmap\ f \lll \pure \\ & ≡ +\join \lll \pure \lll f && \text{$\pure$ is a natural transformation} \\ & ≡ \identity \lll f && \text{By \ref{eq:monad-monoidal-laws-1}} \\ & ≡ f && \text{Left identity} \end{align*} % For \ref{eq:monad-kleisli-laws-2}: \begin{align*} -\bind\ g \rrr \bind\ f & ≡ +\bind\ g \rrr \bind\ f & = \bind\ f \lll \bind\ g - \\ & ≡ + \\ & = %% %%%% -\joinX \lll \fmapX\ g \lll \joinX \lll \fmapX\ f -&& \text{\dots} \\ & ≡ -\joinX \lll \joinX \lll \fmapX^2\ g \lll \fmapX\ f +\join \lll \fmap\ g \lll \join \lll \fmap\ f +\\ & ≡ +\join \lll \join \lll (\fmap \comp \fmap)\ f \lll \fmap\ g && \text{$\join$ is a natural transformation} \\ & ≡ -\joinX\ \lll \fmapX\ \joinX \lll \fmapX^2\ g \lll \fmapX\ f +\join \lll \fmap\ \join \lll (\fmap \comp \fmap)\ f \lll \fmap\ g && \text{By \ref{eq:monad-monoidal-laws-0}} \\ & ≡ -\joinX\ \lll \fmapX\ \joinX\ \lll \fmapX\ (\fmapX\ g) \lll \fmapX\ f +\join \lll \fmap\ \join \lll \fmap\ (\fmap\ f) \lll \fmap\ g && \text{} \\ & ≡ -\joinX \lll \fmapX\ (\joinX \lll \fmapX\ g \lll f) -&& \text{Distributive law for functors} \\ & \equiv +\join \lll \fmap\ (\join \lll \fmap\ f \lll g) +&& \text{Distributive law for functors} \\ & = +\join \lll \fmap\ (\join \lll \fmap\ f \lll g) \\ & = %%%% +\bind\ (\bind\ f \lll g) \\ & = +\bind\ (g \rrr \bind\ f) \\ & = \bind\ (g \fish f) \end{align*} +% +The construction can be found in the module: +\begin{center} + \sourcelink{Cat.Category.Monad.Monoidal} +\end{center} +% \subsubsection{Kleisli to Monoidal} -For the other direction we are given $(\EndoR, \pure, \bind)$ as in +For the other direction we are given $(\omapR, \pure, \bind)$ as in \ref{eq:monad-kleisli-data} satisfying the laws \kleislilaws. For the data of the monoidal formulation we pick: % \begin{align} \begin{split} - \EndoR & \defeq \EndoRX \\ - \pure & \defeq \pureX \\ - \join & \defeq \bind\ \identity + \EndoR & \defeq (\omapR, \bind\ (\pure \lll f)) \\ + \pure & \defeq \pure \\ + \join & \defeq \bind\ \identity \end{split} \end{align} % -Where $\EndoRX \defeq (\bind\ (\pure \lll f), \EndoR)$ and $\pureX \defeq -\bind\ \identity$. We must now show the laws \monoidallaws, but we must also -verify that our choice of $\EndoRX$ actually is a functor. I will ommit this -here. In stead we shall see how these two mappings are indeed inverses. - +We must now not only show the monad laws given for the monoidal +formulation (\monoidallaws), we must also verify that $\EndoR$ is a +functor and that $\pure$ and $\join$ are natural transformations. I +will ommit this here. In stead we shall see how these two mappings are +indeed inverses. The full construction can be found in the module: +\begin{center} +\mbox{\sourcelink{Cat.Category.Monad.Kleisli}} +\end{center} +% \subsubsection{Equivalence} -To prove that the two formulations are equivalent we must demonstrate that the -two mappings sketched above are indeed inverses of each other. If we name the -first mapping $\toKleisli$ and it's proposed inverse $\toMonoidal$ -then we must show: +To prove that the two formulations are equivalent we must demonstrate +that the two mappings sketched above are indeed inverses of each +other. To recap, these maps are: +% +\begin{align*} + \toKleisli & \tp \var{Kleisli} \to \var{Monoidal} \\ + \toKleisli & \defeq \lambda\ (\omapR, \pure, \bind) + \to (\EndoR, \pure, \bind\ \identity) +\end{align*} +% +Where $\EndoR \defeq (\omapR, \bind\ (\pure \lll f))$. The proof that +this is indeed a functor is left implicit as well as the monad laws. +Likewise the proof that $\pure$ and $\bind\ \identity$ are natural +transformations are left implicit. The inverse map will be: +% +\begin{align*} + \toMonoidal & \tp \var{Monoidal} \to \var{Kleisli} \\ + \toMonoidal & \defeq \lambda\ (\EndoR, \pureNT, \joinNT) + \to (\omapR, \pure, \bind) +\end{align*} +% +Where $\bind\ f \defeq \join \lll \fmap\ f$. Again the monad laws are +left implicit. Now we must show: % \begin{align} \label{eq:monad-forwards} @@ -1463,30 +1556,37 @@ then we must show: \toMonoidal \comp \toKleisli & ≡ \identity \end{align} % -For \ref{eq:monad-forwards} let $(\EndoR, \pure, \join)$ be a monad in the -monoidal form. In my formulation the proof that being-a-monad is a proposition -can be found. With this result in place we get an equality principle for -kleisli-monads that say that to equate two such monads it suffices to equate -their data-part. So it suffices to equate the data-parts of the -\ref{eq:monad-forwards}. Such a proof is a triple equation the three projections -of \ref{eq:monad-kleisli-data}. The first two hold definitionally -- essentially -one just wraps and unwraps the morphism in a functor. For the last equation a -little more work is required: +For \ref{eq:monad-forwards} let $(\omapR, \pure, \bind)$ be a monad in +the Kleisli form. Since being-a-monad is a proposition\footnote{The + proof can be found in the implementation.} we get an +equality-principle for kleisli-monads that say that to equate two such +monads it suffices to equate their data-part. So it suffices to equate +the data-parts of the \ref{eq:monad-forwards}. Such a proof is a +triple equating the three projections of \ref{eq:monad-kleisli-data}. +The first two hold definitionally -- essentially one just wraps and +unwraps the morphism in a functor. For the last equation a little more +work is required: % \begin{align*} -\join \lll \fmap\ f & ≡ -\fmap\ f \rrr \join \\ & ≡ +\join \lll \fmap\ f & = +\fmap\ f \rrr \join \\ & = \bind\ (f \rrr \pure) \rrr \bind\ \identity && \text{By definition of $\fmap$ and $\join$} \\ & ≡ \bind\ (f \rrr \pure \fish \identity) && \text{By \ref{eq:monad-kleisli-laws-2}} \\ & ≡ \bind\ (f \rrr \identity) - && \text{By \ref{eq:monad-kleisli-laws-1}} \\ & ≡ + && \text{By \ref{eq:monad-kleisli-laws-1}} \\ & = \bind\ f \end{align*} % -For the other direction we can likewise verify that the maps $\EndoR$, $\bind$, -$\join$, and $\fmap$ are equal. The equality principle for functors gives us -that this is enough to show that the the functor $\EndoR$ we construct is -identical. Similarly for the natural transformations we have that the naturality -condition is a proposition so the paths between the maps are sufficient. +For the other direction (\ref{eq:monad-backwards}) we are given a +monad in the monoidal form; $(\EndoR, \pureNT, \joinNT)$. The various +equality-principles again give us that it is sufficient to equate the +data-part of the above. That is, we only need to verify that the +following pieces of data: $\omapR$, $\fmap$, $\pure$ and $\join$ get +mapped correctly. To see the full details check the implementation in +the module: +% +\begin{center} +\sourcelink{Cat.Category.Monad} +\end{center} diff --git a/doc/macros.tex b/doc/macros.tex index a3939c1..5a280f6 100644 --- a/doc/macros.tex +++ b/doc/macros.tex @@ -9,8 +9,9 @@ %% Alternatively: %% \newcommand{\defeq}{≔} \newcommand{\bN}{\mathbb{N}} -\newcommand{\bC}{\mathbb{C}} -\newcommand{\bX}{\mathbb{X}} +\newcommand{\bC}{ℂ} +\newcommand{\bD}{𝔻} +\newcommand{\bX}{𝕏} % \newcommand{\to}{\rightarrow} %% \newcommand{\mto}{\mapsto} \newcommand{\mto}{\rightarrow} @@ -99,6 +100,10 @@ \newcommand\Endo[1]{\varindex{Endo}\ #1} \newcommand\EndoR{\functor{\mathcal{R}}} \newcommand\omapR{\mathcal{R}} +\newcommand\omapF{\mathcal{F}} +\newcommand\omapG{\mathcal{G}} +\newcommand\FunF{\functor{\omapF}} +\newcommand\FunG{\functor{\omapG}} \newcommand\funExt{\varindex{funExt}} \newcommand{\suc}[1]{\varindex{suc}\ #1} \newcommand{\trans}{\varindex{trans}} @@ -117,3 +122,5 @@ } \newcommand{\gitlink}{\hrefsymb{\docbasepath}{\texttt{\docbasepath}}} \newcommand{\doclink}{\hrefsymb{\sourcebasepath}{\texttt{\sourcebasepath}}} +\newcommand{\clll}{\mathrel{\bC.\mathord{\lll}}} +\newcommand{\dlll}{\mathrel{\bD.\mathord{\lll}}} diff --git a/doc/packages.tex b/doc/packages.tex index cfe33fc..1b434ba 100644 --- a/doc/packages.tex +++ b/doc/packages.tex @@ -140,3 +140,4 @@ -- (1, 1) -- (1, 0.6); } } +\usepackage{ dsfont } diff --git a/src/Cat/Category/Monad.agda b/src/Cat/Category/Monad.agda index dc89634..8efe889 100644 --- a/src/Cat/Category/Monad.agda +++ b/src/Cat/Category/Monad.agda @@ -63,7 +63,8 @@ module _ {ℓa ℓb : Level} (ℂ : Category ℓa ℓb) where f ∎ Kleisli.IsMonad.isDistributive toKleisliIsMonad f g = begin bind g >>> bind f ≡⟨⟩ - (join <<< fmap g) >>> (join <<< fmap f) ≡⟨ isDistributive f g ⟩ + (join <<< fmap f) <<< (join <<< fmap g) ≡⟨ isDistributive f g ⟩ + join <<< fmap (join <<< fmap f <<< g) ≡⟨⟩ bind (g >=> f) ∎ -- Kleisli.IsMonad.isDistributive toKleisliIsMonad = isDistributive From 1683178f1c3acd9f91eb277833e5dbe536244754 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frederik=20Hangh=C3=B8j=20Iversen?= Date: Tue, 22 May 2018 13:48:30 +0200 Subject: [PATCH 16/33] Ignore index-files --- doc/.gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/.gitignore b/doc/.gitignore index dc361bb..b4bbda9 100644 --- a/doc/.gitignore +++ b/doc/.gitignore @@ -10,3 +10,5 @@ *.idx *.ilg *.ind +*.nav +*.snm \ No newline at end of file From 1f2b105f9ddc842d0e47e64edf803173fdd6992e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frederik=20Hangh=C3=B8j=20Iversen?= Date: Tue, 22 May 2018 14:39:42 +0200 Subject: [PATCH 17/33] Provide grpdPiImpl --- src/Cat/Prelude.agda | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/Cat/Prelude.agda b/src/Cat/Prelude.agda index 6835262..2f0a8f2 100644 --- a/src/Cat/Prelude.agda +++ b/src/Cat/Prelude.agda @@ -1,3 +1,4 @@ +{-# OPTIONS --allow-unsolved-metas #-} -- | Custom prelude for this module module Cat.Prelude where @@ -105,3 +106,28 @@ module _ {ℓ : Level} {A : Set ℓ} where ntypeCumulative : ∀ {n m} → n ≤′ m → HasLevel ⟨ n ⟩₋₂ A → HasLevel ⟨ m ⟩₋₂ A ntypeCumulative {m} ≤′-refl lvl = lvl ntypeCumulative {n} {suc m} (≤′-step le) lvl = HasLevel+1 ⟨ m ⟩₋₂ (ntypeCumulative le lvl) + + grpdPi : {ℓa ℓb : Level} {A : Set ℓa} {B : A → Set ℓb} + → ((a : A) → isGrpd (B a)) → isGrpd ((a : A) → (B a)) + grpdPi = piPresNType (S (S (S ⟨-2⟩))) + + grpdPiImpl : {ℓa ℓb : Level} {A : Set ℓa} {B : A → Set ℓb} + → ({a : A} → isGrpd (B a)) → isGrpd ({a : A} → (B a)) + grpdPiImpl {A = A} {B} g = equivPreservesNType {A = Expl} {B = Impl} {n = one} e (grpdPi (λ a → g)) + where + one = (S (S (S ⟨-2⟩))) + t : ({a : A} → HasLevel one (B a)) + t = g + Impl = {a : A} → B a + Expl = (a : A) → B a + expl : Impl → Expl + expl f a = f {a} + impl : Expl → Impl + impl f {a} = f a + e : Expl ≃ Impl + e = impl , (gradLemma impl expl (λ f → refl) (λ f → refl)) + + setGrpd : isSet A → isGrpd A + setGrpd = ntypeCumulative + {suc (suc zero)} {suc (suc (suc zero))} + (≤′-step ≤′-refl) From e7f40eed8a5a43139ee78fa0e1c4dd04299ee94f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frederik=20Hangh=C3=B8j=20Iversen?= Date: Tue, 22 May 2018 15:35:21 +0200 Subject: [PATCH 18/33] Scaffolding for proving groupoid for monads --- src/Cat/Category/Monad/Kleisli.agda | 33 ++++++++++++++++++++++++++++- src/Cat/Prelude.agda | 6 +++--- 2 files changed, 35 insertions(+), 4 deletions(-) diff --git a/src/Cat/Category/Monad/Kleisli.agda b/src/Cat/Category/Monad/Kleisli.agda index 366886b..6cc8cae 100644 --- a/src/Cat/Category/Monad/Kleisli.agda +++ b/src/Cat/Category/Monad/Kleisli.agda @@ -1,7 +1,7 @@ {--- The Kleisli formulation of monads ---} -{-# OPTIONS --cubical #-} +{-# OPTIONS --cubical --allow-unsolved-metas #-} open import Agda.Primitive open import Cat.Prelude @@ -265,3 +265,34 @@ module _ {m n : Monad} (eq : Monad.raw m ≡ Monad.raw n) where Monad≡ : m ≡ n Monad.raw (Monad≡ i) = eq i Monad.isMonad (Monad≡ i) = eqIsMonad i + +module _ where + private + module _ (x y : RawMonad) (p q : x ≡ y) (a b : p ≡ q) where + eq0-helper : isGrpd (Object → Object) + eq0-helper = grpdPi (λ a → ℂ.groupoidObject) + + eq0 : cong (cong RawMonad.omap) a ≡ cong (cong RawMonad.omap) b + eq0 = eq0-helper + (RawMonad.omap x) (RawMonad.omap y) + (cong RawMonad.omap p) (cong RawMonad.omap q) + (cong (cong RawMonad.omap) a) (cong (cong RawMonad.omap) b) + + eq1-helper : (omap : Object → Object) → isGrpd ({X : Object} → ℂ [ X , omap X ]) + eq1-helper f = grpdPiImpl (setGrpd ℂ.arrowsAreSets) + + postulate + eq1 : PathP (λ i → PathP + (λ j → + PathP (λ k → {X : Object} → ℂ [ X , eq0 i j k X ]) + (RawMonad.pure x) (RawMonad.pure y)) + (λ i → RawMonad.pure (p i)) (λ i → RawMonad.pure (q i))) + (cong-d (cong-d RawMonad.pure) a) (cong-d (cong-d RawMonad.pure) b) + + grpdRaw : isGrpd RawMonad + RawMonad.omap (grpdRaw x y p q a b x₁ x₂ x₃) = eq0 x y p q a b x₁ x₂ x₃ + RawMonad.pure (grpdRaw x y p q a b x₁ x₂ x₃) = {!eq1 x y p q a b x₁ x₂ x₃!} + RawMonad.bind (grpdRaw x y p q a b x₁ x₂ x₃) = {!!} + + -- grpdKleisli : isGrpd Monad + -- grpdKleisli = {!!} diff --git a/src/Cat/Prelude.agda b/src/Cat/Prelude.agda index 2f0a8f2..62dd5bd 100644 --- a/src/Cat/Prelude.agda +++ b/src/Cat/Prelude.agda @@ -107,13 +107,13 @@ module _ {ℓ : Level} {A : Set ℓ} where ntypeCumulative {m} ≤′-refl lvl = lvl ntypeCumulative {n} {suc m} (≤′-step le) lvl = HasLevel+1 ⟨ m ⟩₋₂ (ntypeCumulative le lvl) - grpdPi : {ℓa ℓb : Level} {A : Set ℓa} {B : A → Set ℓb} + grpdPi : {ℓb : Level} {B : A → Set ℓb} → ((a : A) → isGrpd (B a)) → isGrpd ((a : A) → (B a)) grpdPi = piPresNType (S (S (S ⟨-2⟩))) - grpdPiImpl : {ℓa ℓb : Level} {A : Set ℓa} {B : A → Set ℓb} + grpdPiImpl : {ℓb : Level} {B : A → Set ℓb} → ({a : A} → isGrpd (B a)) → isGrpd ({a : A} → (B a)) - grpdPiImpl {A = A} {B} g = equivPreservesNType {A = Expl} {B = Impl} {n = one} e (grpdPi (λ a → g)) + grpdPiImpl {B = B} g = equivPreservesNType {A = Expl} {B = Impl} {n = one} e (grpdPi (λ a → g)) where one = (S (S (S ⟨-2⟩))) t : ({a : A} → HasLevel one (B a)) From b116247702df911b278ff9949849273e85216a2e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frederik=20Hangh=C3=B8j=20Iversen?= Date: Tue, 22 May 2018 16:18:22 +0200 Subject: [PATCH 19/33] Kleisli monads are groupoids --- src/Cat/Category/Monad/Kleisli.agda | 60 +++++++++++++++++++++++++---- src/Cat/Prelude.agda | 8 +++- 2 files changed, 59 insertions(+), 9 deletions(-) diff --git a/src/Cat/Category/Monad/Kleisli.agda b/src/Cat/Category/Monad/Kleisli.agda index 6cc8cae..463d3ab 100644 --- a/src/Cat/Category/Monad/Kleisli.agda +++ b/src/Cat/Category/Monad/Kleisli.agda @@ -1,7 +1,7 @@ {--- The Kleisli formulation of monads ---} -{-# OPTIONS --cubical --allow-unsolved-metas #-} +{-# OPTIONS --cubical #-} open import Agda.Primitive open import Cat.Prelude @@ -289,10 +289,56 @@ module _ where (λ i → RawMonad.pure (p i)) (λ i → RawMonad.pure (q i))) (cong-d (cong-d RawMonad.pure) a) (cong-d (cong-d RawMonad.pure) b) - grpdRaw : isGrpd RawMonad - RawMonad.omap (grpdRaw x y p q a b x₁ x₂ x₃) = eq0 x y p q a b x₁ x₂ x₃ - RawMonad.pure (grpdRaw x y p q a b x₁ x₂ x₃) = {!eq1 x y p q a b x₁ x₂ x₃!} - RawMonad.bind (grpdRaw x y p q a b x₁ x₂ x₃) = {!!} - -- grpdKleisli : isGrpd Monad - -- grpdKleisli = {!!} + RawMonad' : Set _ + RawMonad' = Σ (Object → Object) (λ omap + → ({X : Object} → ℂ [ X , omap X ]) + × ({X Y : Object} → ℂ [ X , omap Y ] → ℂ [ omap X , omap Y ]) + ) + grpdRawMonad' : isGrpd RawMonad' + grpdRawMonad' = grpdSig (grpdPi (λ _ → ℂ.groupoidObject)) λ _ → grpdSig (grpdPiImpl (setGrpd ℂ.arrowsAreSets)) (λ _ → grpdPiImpl (grpdPiImpl (grpdPi (λ _ → setGrpd ℂ.arrowsAreSets)))) + toRawMonad : RawMonad' → RawMonad + RawMonad.omap (toRawMonad (a , b , c)) = a + RawMonad.pure (toRawMonad (a , b , c)) = b + RawMonad.bind (toRawMonad (a , b , c)) = c + + IsMonad' : RawMonad' → Set _ + IsMonad' raw = M.IsIdentity × M.IsNatural × M.IsDistributive + where + module M = RawMonad (toRawMonad raw) + + grpdIsMonad' : (m : RawMonad') → isGrpd (IsMonad' m) + grpdIsMonad' m = grpdSig (propGrpd (propIsIdentity (toRawMonad m))) + λ _ → grpdSig (propGrpd (propIsNatural (toRawMonad m))) + λ _ → propGrpd (propIsDistributive (toRawMonad m)) + + Monad' = Σ RawMonad' IsMonad' + grpdMonad' = grpdSig grpdRawMonad' grpdIsMonad' + + toMonad : Monad' → Monad + Monad.raw (toMonad x) = toRawMonad (fst x) + isIdentity (Monad.isMonad (toMonad x)) = fst (snd x) + isNatural (Monad.isMonad (toMonad x)) = fst (snd (snd x)) + isDistributive (Monad.isMonad (toMonad x)) = snd (snd (snd x)) + + fromMonad : Monad → Monad' + fromMonad m = (M.omap , M.pure , M.bind) + , M.isIdentity , M.isNatural , M.isDistributive + where + module M = Monad m + + e : Monad' ≃ Monad + e = toMonad , gradLemma toMonad fromMonad + -- Monads don't have eta-equality + (λ x → λ + { i .Monad.raw → Monad.raw x + ; i .Monad.isMonad → Monad.isMonad x} + ) + λ _ → refl + + grpdMonad : isGrpd Monad + grpdMonad = equivPreservesNType + {n = (S (S (S ⟨-2⟩)))} + e grpdMonad' + where + open import Cubical.NType diff --git a/src/Cat/Prelude.agda b/src/Cat/Prelude.agda index 62dd5bd..a546c75 100644 --- a/src/Cat/Prelude.agda +++ b/src/Cat/Prelude.agda @@ -1,4 +1,3 @@ -{-# OPTIONS --allow-unsolved-metas #-} -- | Custom prelude for this module module Cat.Prelude where @@ -34,7 +33,7 @@ open import Cubical.NType.Properties propIsContr : {ℓ : Level} → {A : Set ℓ} → isProp (isContr A) propIsContr = propHasLevel ⟨-2⟩ -open import Cubical.Sigma using (setSig ; sigPresSet ; sigPresNType) public +open import Cubical.Sigma using (setSig ; sigPresSet ; sigPresNType ; grpdSig) public module _ (ℓ : Level) where -- FIXME Ask if we can push upstream. @@ -131,3 +130,8 @@ module _ {ℓ : Level} {A : Set ℓ} where setGrpd = ntypeCumulative {suc (suc zero)} {suc (suc (suc zero))} (≤′-step ≤′-refl) + + propGrpd : isProp A → isGrpd A + propGrpd = ntypeCumulative + {suc zero} {suc (suc (suc zero))} + (≤′-step (≤′-step ≤′-refl)) From cb0117819b6ad2a8b18be6c2796d9244f69ce6fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frederik=20Hangh=C3=B8j=20Iversen?= Date: Tue, 22 May 2018 16:28:23 +0200 Subject: [PATCH 20/33] Monoidal monads are also groupoids --- src/Cat/Category/Monad.agda | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/Cat/Category/Monad.agda b/src/Cat/Category/Monad.agda index 8efe889..9ff27e1 100644 --- a/src/Cat/Category/Monad.agda +++ b/src/Cat/Category/Monad.agda @@ -231,3 +231,10 @@ module _ {ℓa ℓb : Level} (ℂ : Category ℓa ℓb) where Monoidal≡Kleisli : Monoidal.Monad ≡ Kleisli.Monad Monoidal≡Kleisli = isoToPath Monoidal≊Kleisli + + grpdKleisli : isGrpd Kleisli.Monad + grpdKleisli = Kleisli.grpdMonad + + grpdMonoidal : isGrpd Monoidal.Monad + grpdMonoidal = subst {P = isGrpd} + (sym Monoidal≡Kleisli) grpdKleisli From 9848fac6726e40f21259b820fb3cfe5ce5db5036 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frederik=20Hangh=C3=B8j=20Iversen?= Date: Tue, 22 May 2018 16:31:26 +0200 Subject: [PATCH 21/33] Provide grpdSig --- src/Cat/Prelude.agda | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/Cat/Prelude.agda b/src/Cat/Prelude.agda index a546c75..00064d4 100644 --- a/src/Cat/Prelude.agda +++ b/src/Cat/Prelude.agda @@ -33,7 +33,7 @@ open import Cubical.NType.Properties propIsContr : {ℓ : Level} → {A : Set ℓ} → isProp (isContr A) propIsContr = propHasLevel ⟨-2⟩ -open import Cubical.Sigma using (setSig ; sigPresSet ; sigPresNType ; grpdSig) public +open import Cubical.Sigma using (setSig ; sigPresSet ; sigPresNType) public module _ (ℓ : Level) where -- FIXME Ask if we can push upstream. @@ -135,3 +135,8 @@ module _ {ℓ : Level} {A : Set ℓ} where propGrpd = ntypeCumulative {suc zero} {suc (suc (suc zero))} (≤′-step (≤′-step ≤′-refl)) + +module _ {ℓa ℓb : Level} {A : Set ℓa} {B : A → Set ℓb} where + open TLevel + grpdSig : isGrpd A → (∀ a → isGrpd (B a)) → isGrpd (Σ A B) + grpdSig = sigPresNType {n = S (S (S ⟨-2⟩))} From 879f5bab52f1c1d2d4866a738f41d1739e82f226 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frederik=20Hangh=C3=B8j=20Iversen?= Date: Tue, 22 May 2018 18:01:03 +0200 Subject: [PATCH 22/33] Use `fromIsomorphism` globally --- src/Cat/Categories/Rel.agda | 25 ++++--------------------- src/Cat/Category/Monad/Kleisli.agda | 15 +++++++++------ src/Cat/Category/Monad/Voevodsky.agda | 12 ++++++------ 3 files changed, 19 insertions(+), 33 deletions(-) diff --git a/src/Cat/Categories/Rel.agda b/src/Cat/Categories/Rel.agda index 3aa4e59..f334c30 100644 --- a/src/Cat/Categories/Rel.agda +++ b/src/Cat/Categories/Rel.agda @@ -2,6 +2,7 @@ module Cat.Categories.Rel where open import Cat.Prelude hiding (Rel) +open import Cat.Equivalence open import Cat.Category @@ -61,15 +62,9 @@ module _ {A B : Set} {S : Subset (A × B)} (ab : A × B) where lem0 = (λ a'' a≡a'' → ∀ a''b∈S → (forwards ∘ backwards) (a'' , a≡a'' , a''b∈S) ≡ (a'' , a≡a'' , a''b∈S)) lem1 = (λ z₁ → cong (\ z → a , refl , z) (pathJprop (\ y _ → y) z₁)) - isequiv : isEquiv - (Σ[ a' ∈ A ] (a , a') ∈ Diag A × (a' , b) ∈ S) - ((a , b) ∈ S) - backwards - isequiv y = gradLemma backwards forwards fwd-bwd bwd-fwd y - equi : (Σ[ a' ∈ A ] (a , a') ∈ Diag A × (a' , b) ∈ S) ≃ (a , b) ∈ S - equi = backwards , isequiv + equi = fromIsomorphism _ _ (backwards , forwards , funExt bwd-fwd , funExt fwd-bwd) ident-r : (Σ[ a' ∈ A ] (a , a') ∈ Diag A × (a' , b) ∈ S) ≡ (a , b) ∈ S @@ -95,15 +90,9 @@ module _ {A B : Set} {S : Subset (A × B)} (ab : A × B) where lem0 = (λ b'' b≡b'' → (ab''∈S : (a , b'') ∈ S) → (forwards ∘ backwards) (b'' , ab''∈S , sym b≡b'') ≡ (b'' , ab''∈S , sym b≡b'')) lem1 = (λ ab''∈S → cong (λ φ → b , φ , refl) (pathJprop (λ y _ → y) ab''∈S)) - isequiv : isEquiv - (Σ[ b' ∈ B ] (a , b') ∈ S × (b' , b) ∈ Diag B) - ((a , b) ∈ S) - backwards - isequiv ab∈S = gradLemma backwards forwards bwd-fwd fwd-bwd ab∈S - equi : (Σ[ b' ∈ B ] (a , b') ∈ S × (b' , b) ∈ Diag B) ≃ ab ∈ S - equi = backwards , isequiv + equi = fromIsomorphism _ _ (backwards , (forwards , funExt fwd-bwd , funExt bwd-fwd)) ident-l : (Σ[ b' ∈ B ] (a , b') ∈ S × (b' , b) ∈ Diag B) ≡ ab ∈ S @@ -133,15 +122,9 @@ module _ {A B C D : Set} {S : Subset (A × B)} {R : Subset (B × C)} {Q : Subset bwd-fwd : (x : Q⊕⟨R⊕S⟩) → (bwd ∘ fwd) x ≡ x bwd-fwd x = refl - isequiv : isEquiv - (Σ[ c ∈ C ] (Σ[ b ∈ B ] (a , b) ∈ S × (b , c) ∈ R) × (c , d) ∈ Q) - (Σ[ b ∈ B ] (a , b) ∈ S × (Σ[ c ∈ C ] (b , c) ∈ R × (c , d) ∈ Q)) - fwd - isequiv = gradLemma fwd bwd fwd-bwd bwd-fwd - equi : (Σ[ c ∈ C ] (Σ[ b ∈ B ] (a , b) ∈ S × (b , c) ∈ R) × (c , d) ∈ Q) ≃ (Σ[ b ∈ B ] (a , b) ∈ S × (Σ[ c ∈ C ] (b , c) ∈ R × (c , d) ∈ Q)) - equi = fwd , isequiv + equi = fromIsomorphism _ _ (fwd , bwd , funExt bwd-fwd , funExt fwd-bwd) -- isAssociativec : Q + (R + S) ≡ (Q + R) + S is-isAssociative : (Σ[ c ∈ C ] (Σ[ b ∈ B ] (a , b) ∈ S × (b , c) ∈ R) × (c , d) ∈ Q) diff --git a/src/Cat/Category/Monad/Kleisli.agda b/src/Cat/Category/Monad/Kleisli.agda index 463d3ab..0fd6e3d 100644 --- a/src/Cat/Category/Monad/Kleisli.agda +++ b/src/Cat/Category/Monad/Kleisli.agda @@ -5,6 +5,7 @@ The Kleisli formulation of monads open import Agda.Primitive open import Cat.Prelude +open import Cat.Equivalence open import Cat.Category open import Cat.Category.Functor as F @@ -328,13 +329,15 @@ module _ where module M = Monad m e : Monad' ≃ Monad - e = toMonad , gradLemma toMonad fromMonad + e = fromIsomorphism _ _ (toMonad , fromMonad , (funExt λ _ → refl) , funExt eta-refl) + where -- Monads don't have eta-equality - (λ x → λ - { i .Monad.raw → Monad.raw x - ; i .Monad.isMonad → Monad.isMonad x} - ) - λ _ → refl + eta-refl : (x : Monad) → toMonad (fromMonad x) ≡ x + eta-refl = + (λ x → λ + { i .Monad.raw → Monad.raw x + ; i .Monad.isMonad → Monad.isMonad x} + ) grpdMonad : isGrpd Monad grpdMonad = equivPreservesNType diff --git a/src/Cat/Category/Monad/Voevodsky.agda b/src/Cat/Category/Monad/Voevodsky.agda index 8d3b75f..7bedab1 100644 --- a/src/Cat/Category/Monad/Voevodsky.agda +++ b/src/Cat/Category/Monad/Voevodsky.agda @@ -1,11 +1,11 @@ {- This module provides construction 2.3 in [voe] -} -{-# OPTIONS --cubical --caching #-} +{-# OPTIONS --cubical --allow-unsolved-metas #-} module Cat.Category.Monad.Voevodsky where - open import Cat.Prelude +open import Cat.Equivalence open import Cat.Category open import Cat.Category.Functor as F @@ -203,8 +203,8 @@ module voe {ℓa ℓb : Level} (ℂ : Category ℓa ℓb) where K.Monad.raw (lemma m i) = K.Monad.raw m K.Monad.isMonad (lemma m i) = K.Monad.isMonad m - voe-isEquiv : isEquiv (§2-3.§1 omap pure) (§2-3.§2 omap pure) forth - voe-isEquiv = gradLemma forth back forthEq backEq - equiv-2-3 : §2-3.§1 omap pure ≃ §2-3.§2 omap pure - equiv-2-3 = forth , voe-isEquiv + equiv-2-3 = fromIsomorphism _ _ + ( forth , back + , funExt backEq , funExt forthEq + ) From 251fcf196651e6999af63e8c5803a7a13b058efd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frederik=20Hangh=C3=B8j=20Iversen?= Date: Wed, 23 May 2018 17:34:50 +0200 Subject: [PATCH 23/33] Add backlog based on comments from Andrea, implement some of them --- doc/BACKLOG.md | 73 ++++++++++++- doc/appendix/abstract-funext.tex | 74 +++++++++++++ doc/discussion.tex | 143 +++++++++++++++++--------- doc/feedback-meeting-andrea.txt | 9 ++ doc/introduction.tex | 90 +++++++++------- doc/macros.tex | 3 + doc/main.tex | 7 +- src/Cat/Category/Monad.agda | 2 +- src/Cat/Category/Monad/Voevodsky.agda | 66 +++++++++--- 9 files changed, 360 insertions(+), 107 deletions(-) create mode 100644 doc/appendix/abstract-funext.tex create mode 100644 doc/feedback-meeting-andrea.txt diff --git a/doc/BACKLOG.md b/doc/BACKLOG.md index 8bf5f45..fc8de53 100644 --- a/doc/BACKLOG.md +++ b/doc/BACKLOG.md @@ -3,5 +3,74 @@ Talk about structure of library: What can I say about reusability? -Misc -==== +Meeting with Andrea May 18th +============================ + +App. 2 in HoTT gives typing rule for pathJ including a computational +rule for it. + +If you have this computational rule definitionally, then you wouldn't +need to use `pathJprop`. + +In discussion-section I mention HITs. I should remove this or come up +with a more elaborate example of something you could do, e.g. +something with pushouts in the category of sets. + +The type Prop is a type where terms are *judgmentally* equal not just +propositionally so. + +Maybe mention that Andreas Källberg is working on proving the +initiality conjecture. + +Intensional Type Theory (ITT): Judgmental equality is decidable + +Extensional Type Theory (ETT): Reflection is enough to make judgmental +equality undecidable. + + Reflection : a ≡ b → a = b + +ITT does not have reflections. + +HTT ~ ITT + axiomatized univalence +Agda ~ ITT + K-rule +Coq ~ ITT (no K-rule) +Cubical Agda ~ ITT + Path + Glue + +Prop is impredicative in Coq (whatever that means) + +Prop ≠ hProp + +Comments about abstract +----- + +Pattern matching for paths (?) + +Intro +----- +Main feature of judgmental equality is the conversion rule. + +Conor explained: K + eliminators ≡ pat. matching + +Explain jugmental equality independently of type-checking + +Soundness for equality means that if `x = y` then `x` and `y` must be +equal according to the theory/model. + +Decidability of `=` is a necessary condition for typechecking to be +decidable. + +Canonicity is a nice-to-have though without canonicity terms can get +stuck. If we postulate results about judgmental equality. E.g. funext, +then we can construct a term of type natural number that is not a +numeral. Therefore stating canonicity with natural numbers: + + ∀ t . ⊢ t : N , ∃ n : N . ⊢ t = sⁿ 0 : N + +is a sufficient condition to get a well-behaved equality. + +Eta-equality for RawFunctor means that the associative law for +functors hold definitionally. + +Computational property for funExt is only relevant in two places in my +whole formulation. Univalence and gradLemma does not influence any +proofs. diff --git a/doc/appendix/abstract-funext.tex b/doc/appendix/abstract-funext.tex new file mode 100644 index 0000000..dafb81f --- /dev/null +++ b/doc/appendix/abstract-funext.tex @@ -0,0 +1,74 @@ +\chapter{Abstract functional extensionality} +\label{app:abstract-funext} +In two places in my formalization was the computational behaviours of +functional extensionality used. The reduction behaviour can be +disabled by marking functional extensionality as abstract. Below the +fully normalized goal and context with functional extensionality +marked abstract has been shown. The excerpts are from the module +% +\begin{center} +\sourcelink{Cat.Category.Monad.Voevodsky} +\end{center} +% +where this is also written as a comment next to the proofs. When +functional extensionality is not abstract the goal and current value +are the same. It is of course necessary to show the fully normalized +goal and context otherwise the reduction behaviours is not forced. + +\subsubsection*{First goal} +Goal: +\begin{verbatim} +PathP (λ _ → §2-3.§2 omap (λ {z} → pure)) +(§2-fromMonad + (.Cat.Category.Monad.toKleisli ℂ + (.Cat.Category.Monad.toMonoidal ℂ (§2-3.§2.toMonad m)))) +(§2-fromMonad (§2-3.§2.toMonad m)) +\end{verbatim} +Have: +\begin{verbatim} +PathP +(λ i → + §2-3.§2 K.IsMonad.omap + (K.RawMonad.pure + (K.Monad.raw + (funExt (λ m₁ → K.Monad≡ (.Cat.Category.Monad.toKleisliRawEq ℂ m₁)) + i (§2-3.§2.toMonad m))))) +(§2-fromMonad + (.Cat.Category.Monad.toKleisli ℂ + (.Cat.Category.Monad.toMonoidal ℂ (§2-3.§2.toMonad m)))) +(§2-fromMonad (§2-3.§2.toMonad m)) +\end{verbatim} +\subsubsection*{Second goal} +Goal: +\begin{verbatim} +PathP (λ _ → §2-3.§1 omap (λ {X} → pure)) +(§1-fromMonad + (.Cat.Category.Monad.toMonoidal ℂ + (.Cat.Category.Monad.toKleisli ℂ (§2-3.§1.toMonad m)))) +(§1-fromMonad (§2-3.§1.toMonad m)) +\end{verbatim} +Have: +\begin{verbatim} +PathP +(λ i → + §2-3.§1 + (RawFunctor.omap + (Functor.raw + (M.RawMonad.R + (M.Monad.raw + (funExt + (λ m₁ → M.Monad≡ (.Cat.Category.Monad.toMonoidalRawEq ℂ m₁)) i + (§2-3.§1.toMonad m)))))) + (λ {X} → + fst + (M.RawMonad.pureNT + (M.Monad.raw + (funExt + (λ m₁ → M.Monad≡ (.Cat.Category.Monad.toMonoidalRawEq ℂ m₁)) i + (§2-3.§1.toMonad m)))) + X)) +(§1-fromMonad + (.Cat.Category.Monad.toMonoidal ℂ + (.Cat.Category.Monad.toKleisli ℂ (§2-3.§1.toMonad m)))) +(§1-fromMonad (§2-3.§1.toMonad m)) +\end{verbatim} diff --git a/doc/discussion.tex b/doc/discussion.tex index 58c687c..e021ff5 100644 --- a/doc/discussion.tex +++ b/doc/discussion.tex @@ -1,55 +1,99 @@ \chapter{Perspectives} \section{Discussion} -In the previous chapter the practical aspects of proving things in Cubical Agda -were highlighted. I also demonstrated the usefulness of separating ``laws'' from -``data''. One of the reasons for this is that dependencies within types can lead -to very complicated goals. One technique for alleviating this was to prove that -certain types are mere propositions. +In the previous chapter the practical aspects of proving things in +Cubical Agda were highlighted. I also demonstrated the usefulness of +separating ``laws'' from ``data''. One of the reasons for this is that +dependencies within types can lead to very complicated goals. One +technique for alleviating this was to prove that certain types are +mere propositions. \subsection{Computational properties} -Another aspect (\TODO{That I actually did not highlight very well in the - previous chapter}) is the computational nature of paths. Say we have -formalized this common result about monads: +The new contribution of cubical Agda is that it has a constructive +proof of functional extensionality\index{functional extensionality} +and univalence\index{univalence}. This means that in particular that +the type checker can reduce terms defined with these theorems. So one +interesting result of this development is how much this influenced the +development. In particular having a functional extensionality that +``computes'' should simplify some proofs. -\TODO{Some equation\ldots} +I have tested this theory by using a feature of Agda where one can +mark certain bindings as being \emph{abstract}. This means that the +type-checker will not try to reduce that term further when +type-checking is performed. I tried making univalence and functional +extensionality abstract. It turns out that the conversion behaviour of +univalence is not used anywhere. For functional extensionality there +are two places in the whole solution where the reduction behaviour is +used to simplify some proofs. This is in showing that the maps between +the two formulations of monads are inverses. See the notes in this +module: +% +\begin{center} +\sourcelink{Cat.Category.Monad.Voevodsky} +\end{center} +% +I've also put this in a source listing in \ref{app:abstract-funext}. I +will not reproduce it in full here as the type is quite involved. The +method used to find in what places the computational behaviour of +these proofs are needed has the caveat of only working for places that +directly or transitively uses these two proofs. Fortunately though the +code is structured in such a way that this should be the case. +Nonetheless it is quite surprising that this computational behaviours +is not used more widely in the formalization. -By transporting this to the Kleisli formulation we get a result that we can use -to compute with. This is particularly useful because the Kleisli formulation -will be more familiar to programmers e.g.\ those coming from a background in -Haskell. Whereas the theory usually talks about monoidal monads. - -\TODO{Mention that with postulates we cannot do this} +Barring this, however, the computational behaviour of paths can still +be useful. E.g. if a programmer want's to reuse functions that operate +on a monoidal monads to work with a monad in the Kleisli form that +this programmer has specified. To make this idea concrete, say we are +given some function $f \tp \Kleisli \to T$ having a path between $p +\tp \Monoidal \equiv \Kleisli$ induces a map $\coe\ p \tp \Monoidal +\to \Kleisli$. We can compose $f$ with this map to get $f \comp +\coe\ p \tp \Monoidal \to T$. Of course, since that map was +constructed with an isomorphism these maps already exist and could be +used directly. So this is arguably only interesting when one wants to +prove properties of such functions. \subsection{Reusability of proofs} -The previous example also illustrate how univalence unifies two otherwise -disparate areas: The category-theoretic study of monads; and monads as in -functional programming. Univalence thus allows one to reuse proofs. You could -say that univalence gives the developer two proofs for the price of one. +The previous example illustrate how univalence unifies two otherwise +disparate areas: The category-theoretic study of monads; and monads as +in functional programming. Univalence thus allows one to reuse proofs. +You could say that univalence gives the developer two proofs for the +price of one. As an illustration of this I proved that monads are +groupoids. I initially proved this for the Kleisli +formulation\footnote{Actually doing this directly turned out to be + tricky as well, so I defined an equivalent formulation which was not + formulated with a record, but purely with $\sum$-types.}. Since the +two formulations are equal under univalence, substitution directly +gives us that this also holds for the monoidal formulation. This of +course generalizes to any family $P \tp 𝒰 → 𝒰$ where $P$ is inhabited +at either formulation (i.e.\ either $P\ \Monoidal$ or $P\ \Kleisli$ +holds). The introduction (section \S\ref{sec:context}) mentioned an often employed-technique for enabling extensional equalities is to use the -setoid-interpretation. Nowhere in this formalization has this been necessary, -$\Path$ has been used globally in the project as propositional equality. One -interesting place where this becomes apparent is in interfacing with the Agda -standard library. Multiple definitions in the Agda standard library have been -designed with the setoid-interpretation in mind. E.g. the notion of ``unique +setoid-interpretation. Nowhere in this formalization has this been +necessary, $\Path$ has been used globally in the project as +propositional equality. One interesting place where this becomes +apparent is in interfacing with the Agda standard library. Multiple +definitions in the Agda standard library have been designed with the +setoid-interpretation in mind. E.g. the notion of ``unique existential'' is indexed by a relation that should play the role of -propositional equality. Likewise for equivalence relations, they are indexed, -not only by the actual equivalence relation, but also by another relation that -serve as propositional equality. -%% Unfortunately we cannot use the definition of equivalences found in the -%% standard library to do equational reasoning directly. The reason for this is -%% that the equivalence relation defined there must be a homogenous relation, -%% but paths are heterogeneous relations. +propositional equality. Likewise for equivalence relations, they are +indexed, not only by the actual equivalence relation, but also by +another relation that serve as propositional equality. +%% Unfortunately we cannot use the definition of equivalences found in +%% the standard library to do equational reasoning directly. The +%% reason for this is that the equivalence relation defined there must +%% be a homogenous relation, but paths are heterogeneous relations. -In the formalization at present a significant amount of energy has been put -towards proving things that would not have been needed in classical Agda. The -proofs that some given type is a proposition were provided as a strategy to -simplify some otherwise very complicated proofs (e.g. -\ref{eq:proof-prop-IsPreCategory} and \label{eq:productPath}). Often these -proofs would not be this complicated. If the J-rule holds definitionally the -proof-assistant can help simplify these goals considerably. The lack of the -J-rule has a significant impact on the complexity of these kinds of proofs. +In the formalization at present a significant amount of energy has +been put towards proving things that would not have been needed in +classical Agda. The proofs that some given type is a proposition were +provided as a strategy to simplify some otherwise very complicated +proofs (e.g. \ref{eq:proof-prop-IsPreCategory} +and \label{eq:productPath}). Often these proofs would not be this +complicated. If the J-rule holds definitionally the proof-assistant +can help simplify these goals considerably. The lack of the J-rule has +a significant impact on the complexity of these kinds of proofs. \TODO{Universe levels.} @@ -60,15 +104,16 @@ Jesper Cockx' work extending the universe-level-laws for Agda and the \subsection{Compiling Cubical Agda} \label{sec:compiling-cubical-agda} -Compilation of program written in Cubical Agda is currently not supported. One -issue here is that the backends does not provide an implementation for the -cubical primitives (such as the path-type). This means that even though the -path-type gives us a computational interpretation of functional extensionality, -univalence, transport, etc., we do not have a way of actually using this to -compile our programs that use these primitives. It would be interesting to see -practical applications of this. The path between monads that this library -exposes could provide one particularly interesting case-study. +Compilation of program written in Cubical Agda is currently not +supported. One issue here is that the backends does not provide an +implementation for the cubical primitives (such as the path-type). +This means that even though the path-type gives us a computational +interpretation of functional extensionality, univalence, transport, +etc., we do not have a way of actually using this to compile our +programs that use these primitives. It would be interesting to see +practical applications of this. The path between monads that this +library exposes could provide one particularly interesting case-study. \subsection{Higher inductive types} -This library has not explored the usefulness of higher inductive types in the -context of Category Theory. +This library has not explored the usefulness of higher inductive types +in the context of Category Theory. diff --git a/doc/feedback-meeting-andrea.txt b/doc/feedback-meeting-andrea.txt new file mode 100644 index 0000000..1e1eca1 --- /dev/null +++ b/doc/feedback-meeting-andrea.txt @@ -0,0 +1,9 @@ +App. 2 in HoTT gives typing rule for pathJ including a computational +rule for it. + +If you have this computational rule definitionally, then you wouldn't +need to use `pathJprop`. + +In discussion-section I mention HITs. I should remove this or come up +with a more elaborate example of something you could do, e.g. +something with pushouts in the category of sets. diff --git a/doc/introduction.tex b/doc/introduction.tex index 2ac7baf..853da02 100644 --- a/doc/introduction.tex +++ b/doc/introduction.tex @@ -1,42 +1,64 @@ \chapter{Introduction} -This thesis is a case-study in the application of Cubical Agda in the +This thesis is a case-study in the application of cubical Agda in the context of category theory. At the center of this is the notion of \nomenindex{equality}. In type-theory there are two pervasive notions of equality: \nomenindex{judgmental equality} and \nomenindex{propositional equality}. Judgmental equality is a property -of the type system, it is a property that is automatically checked by -a type checker. As such there are some properties judgmental -equalities must crucially have. It must be \nomenindex{decidable}, -\nomenindex{sound}, enjoy \nomenindex{canonicity} and be a -\nomen{congruence relation}. Being decidable simply means that that an -algorithm exists to decide whether two terms are equal. For any -practical implementation the decidability must also be effectively -computable. Soundness means that things judged to be equal actually -\emph{are} considered equal. It must be a congruence relation because -otherwise the relation certainly does not adhere to our notion of -equality. One would be able to conclude things like: $x \nequiv y -\rightarrow f\ x \equiv f\ y$. Canonicity will be explained later in -this introduction after we've seen an example of judgmental- and -propositional equality at play for a simple example.\TODO{How to - motivate canonicity for equality}. +of the type system. Judgmental equality on the other hand is usually +defined \emph{within} the system. When introducing definitions this +report will use the notation $\defeq$. Judgmental equalities written +$=$. For propositional equalities the notation $\equiv$ is used. + +For judgmental equality there are some properties that it must +satisfy. \nomenindex{sound}, enjoy \nomenindex{canonicity} and be a +\nomen{congruence relation}. Soundness means that things judged to be +equal are equal with respects to the model of the theory (the meta +theory). It must be a congruence relation because otherwise the +relation certainly does not adhere to our notion of equality. One +would be able to conclude things like: $x \equiv y \rightarrow f\ x +\nequiv f\ y$. Canonicity means that any well typed term evaluates to +a \emph{canonical} form. For example for a closed term $e \tp \bN$ it +will be the case that $e$ reduces to $n$ applications of +$\mathit{suc}$ to $0$ for some $n$; $e = \mathit{suc}^n\ 0$. Without +canonicity terms in the language can get ``stuck'' -- meaning that +they do not reduce to a canonical form. + +To work as a programming languages it is necessary for judgmental +equality to be \nomenindex{decidable}. Being decidable simply means +that that an algorithm exists to decide whether two terms are equal. +For any practical implementation the decidability must also be +effectively computable. For propositional equality the decidability requirement is relaxed. It is not in general possible to decide the correctness of logical propositions (cf.\ Hilbert's \emph{entscheidigungsproblem}). -Propositional equality are provided by the developer. When introducing -definitions this report will use the notation $\defeq$. Judgmental -equalities written $=$. For propositional equalities the notation -$\equiv$ is used. + +There are two flavors of type-theory. \emph{Intensional-} and +\emph{extensional-} type theory. Identity types in extensional type +theory are required to be \nomen{propositions}{proposition}. That is, +a type with at most one inhabitant. In extensional type thoery the +principle of reflection +% +$$a ≡ b → a = b$$ +% +is enough to make type checking undecidable. This report focuses on +Agda which at a glance can be thought of a version of intensional type +theory. Pattern-matching in regular Agda let's one prove +\nomenindex{axiom K}. Axiom K states that any two identity proofs are +propositionally identical. The usual notion of propositional equality in \nomenindex{Intensional Type Theory} (ITT) is quite restrictive. In the next section a few motivating examples will highlight this. There exist techniques to circumvent these problems, as we shall see. This thesis will explore an extension to Agda that redefines the notion of propositional -equality and as such is an alternative to these other techniques. What -makes this extension particularly interesting is that it gives a -\emph{constructive} interpretation of univalence. What this means will -be elaborated in the following sections. +equality and as such is an alternative to these other techniques. The +extension is called cubical Agda. Cubical Agda drops Axiom K as this +does not permit \nomenindex{functional extensionality} and +\nomenindex{univalence}. What makes this extension particularly +interesting is that it gives a \emph{constructive} interpretation of +univalence. What all this means will be elaborated in the following +sections. % \section{Motivating examples} % @@ -192,22 +214,16 @@ There are alternative approaches to working in a cubical setting where one can still have univalence and functional extensionality. One option is to postulate these as axioms. This approach, however, has other shortcomings, e.g. you lose \nomenindex{canonicity} -(\TODO{Pageno!} \cite{huber-2016}). Canonicity means that any well -typed term evaluates to a \emph{canonical} form. For example for a -closed term $e \tp \bN$ it will be the case that $e$ reduces to $n$ -applications of $\mathit{suc}$ to $0$ for some $n$; $e = -\mathit{suc}^n\ 0$. Without canonicity terms in the language can get -``stuck'' -- meaning that they do not reduce to a canonical form. +(\TODO{Pageno!} \cite{huber-2016}). Another approach is to use the \emph{setoid interpretation} of type theory (\cite{hofmann-1995,huber-2016}). With this approach one works -with -\nomenindex{extensional sets} $(X, \sim)$, that is a type $X \tp \MCU$ -and an equivalence relation $\sim\ \tp X \to X \to \MCU$ on that type. -Under the setoid interpretation the equivalence relation serve as a -sort of ``local'' propositional equality. Since the developer gets to -pick this relation it is not guaranteed to be a congruence relation -a priori. So this must be verified manually by the developer. +with \nomenindex{extensional sets} $(X, \sim)$, that is a type $X \tp +\MCU$ and an equivalence relation $\sim\ \tp X \to X \to \MCU$ on that +type. Under the setoid interpretation the equivalence relation serve +as a sort of ``local'' propositional equality. Since the developer +gets to pick this relation it is not guaranteed to be a congruence +relation a priori. So this must be verified manually by the developer. Furthermore, functions between different setoids must be shown to be setoid homomorphism, that is; they preserve the relation. diff --git a/doc/macros.tex b/doc/macros.tex index 5a280f6..4d872b0 100644 --- a/doc/macros.tex +++ b/doc/macros.tex @@ -124,3 +124,6 @@ \newcommand{\doclink}{\hrefsymb{\sourcebasepath}{\texttt{\sourcebasepath}}} \newcommand{\clll}{\mathrel{\bC.\mathord{\lll}}} \newcommand{\dlll}{\mathrel{\bD.\mathord{\lll}}} +\newcommand\coe{\varindex{coe}} +\newcommand\Monoidal{\varindex{Monoidal}} +\newcommand\Kleisli{\varindex{Kleisli}} diff --git a/doc/main.tex b/doc/main.tex index 26b62de..8b5e7ff 100644 --- a/doc/main.tex +++ b/doc/main.tex @@ -62,9 +62,10 @@ \nocite{coquand-2013} \bibliography{refs} -%% \begin{appendices} -%% \setcounter{page}{1} -%% \pagenumbering{roman} +\begin{appendices} +\setcounter{page}{1} +\pagenumbering{roman} +\input{appendix/abstract-funext.tex} %% \input{sources.tex} %% \input{planning.tex} %% \input{halftime.tex} diff --git a/src/Cat/Category/Monad.agda b/src/Cat/Category/Monad.agda index 9ff27e1..87ee931 100644 --- a/src/Cat/Category/Monad.agda +++ b/src/Cat/Category/Monad.agda @@ -198,7 +198,7 @@ module _ {ℓa ℓb : Level} (ℂ : Category ℓa ℓb) where Req = Functor≡ rawEq pureTEq : Monoidal.RawMonad.pureT (toMonoidalRaw (toKleisli m)) ≡ pureT - pureTEq = funExt (λ X → refl) + pureTEq = refl pureNTEq : (λ i → NaturalTransformation Functors.identity (Req i)) [ Monoidal.RawMonad.pureNT (toMonoidalRaw (toKleisli m)) ≡ pureNT ] diff --git a/src/Cat/Category/Monad/Voevodsky.agda b/src/Cat/Category/Monad/Voevodsky.agda index 7bedab1..92e72aa 100644 --- a/src/Cat/Category/Monad/Voevodsky.agda +++ b/src/Cat/Category/Monad/Voevodsky.agda @@ -1,7 +1,7 @@ {- This module provides construction 2.3 in [voe] -} -{-# OPTIONS --cubical --allow-unsolved-metas #-} +{-# OPTIONS --cubical #-} module Cat.Category.Monad.Voevodsky where open import Cat.Prelude @@ -152,7 +152,26 @@ module voe {ℓa ℓb : Level} (ℂ : Category ℓa ℓb) where §2-fromMonad ((Monoidal→Kleisli ∘ Kleisli→Monoidal) (§2-3.§2.toMonad m)) - ≡⟨ (cong-d (\ φ → §2-fromMonad (φ (§2-3.§2.toMonad m))) re-ve) ⟩ + -- Below is the fully normalized goal and context with + -- `funExt` made abstract. + -- + -- Goal: PathP (λ _ → §2-3.§2 omap (λ {z} → pure)) + -- (§2-fromMonad + -- (.Cat.Category.Monad.toKleisli ℂ + -- (.Cat.Category.Monad.toMonoidal ℂ (§2-3.§2.toMonad m)))) + -- (§2-fromMonad (§2-3.§2.toMonad m)) + -- Have: PathP + -- (λ i → + -- §2-3.§2 K.IsMonad.omap + -- (K.RawMonad.pure + -- (K.Monad.raw + -- (funExt (λ m₁ → K.Monad≡ (.Cat.Category.Monad.toKleisliRawEq ℂ m₁)) + -- i (§2-3.§2.toMonad m))))) + -- (§2-fromMonad + -- (.Cat.Category.Monad.toKleisli ℂ + -- (.Cat.Category.Monad.toMonoidal ℂ (§2-3.§2.toMonad m)))) + -- (§2-fromMonad (§2-3.§2.toMonad m)) + ≡⟨ ( cong-d {x = Monoidal→Kleisli ∘ Kleisli→Monoidal} {y = idFun K.Monad} (\ φ → §2-fromMonad (φ (§2-3.§2.toMonad m))) re-ve) ⟩ (§2-fromMonad ∘ §2-3.§2.toMonad) m ≡⟨ lemma ⟩ m ∎ @@ -174,24 +193,41 @@ module voe {ℓa ℓb : Level} (ℂ : Category ℓa ℓb) where §1-fromMonad ((Kleisli→Monoidal ∘ Monoidal→Kleisli) (§2-3.§1.toMonad m)) + -- Below is the fully normalized `agda2-goal-and-context` + -- with `funExt` made abstract. + -- + -- Goal: PathP (λ _ → §2-3.§1 omap (λ {X} → pure)) + -- (§1-fromMonad + -- (.Cat.Category.Monad.toMonoidal ℂ + -- (.Cat.Category.Monad.toKleisli ℂ (§2-3.§1.toMonad m)))) + -- (§1-fromMonad (§2-3.§1.toMonad m)) + -- Have: PathP + -- (λ i → + -- §2-3.§1 + -- (RawFunctor.omap + -- (Functor.raw + -- (M.RawMonad.R + -- (M.Monad.raw + -- (funExt + -- (λ m₁ → M.Monad≡ (.Cat.Category.Monad.toMonoidalRawEq ℂ m₁)) i + -- (§2-3.§1.toMonad m)))))) + -- (λ {X} → + -- fst + -- (M.RawMonad.pureNT + -- (M.Monad.raw + -- (funExt + -- (λ m₁ → M.Monad≡ (.Cat.Category.Monad.toMonoidalRawEq ℂ m₁)) i + -- (§2-3.§1.toMonad m)))) + -- X)) + -- (§1-fromMonad + -- (.Cat.Category.Monad.toMonoidal ℂ + -- (.Cat.Category.Monad.toKleisli ℂ (§2-3.§1.toMonad m)))) + -- (§1-fromMonad (§2-3.§1.toMonad m)) ≡⟨ (cong-d (\ φ → §1-fromMonad (φ (§2-3.§1.toMonad m))) ve-re) ⟩ §1-fromMonad (§2-3.§1.toMonad m) ≡⟨ lemmaz ⟩ m ∎ where - -- having eta equality on causes roughly the same work as checking this proof of foo, - -- which is quite expensive because it ends up reducing complex terms. - - -- rhs = §1-fromMonad (Kleisli→Monoidal ((Monoidal→Kleisli (§2-3.§1.toMonad m)))) - -- foo : §1-fromMonad (Kleisli→Monoidal (§2-3.§2.toMonad (§2-fromMonad (Monoidal→Kleisli (§2-3.§1.toMonad m))))) - -- ≡ §1-fromMonad (Kleisli→Monoidal ((Monoidal→Kleisli (§2-3.§1.toMonad m)))) - -- §2-3.§1.fmap (foo i) = §2-3.§1.fmap rhs - -- §2-3.§1.join (foo i) = §2-3.§1.join rhs - -- §2-3.§1.RisFunctor (foo i) = §2-3.§1.RisFunctor rhs - -- §2-3.§1.pureN (foo i) = §2-3.§1.pureN rhs - -- §2-3.§1.joinN (foo i) = §2-3.§1.joinN rhs - -- §2-3.§1.isMonad (foo i) = §2-3.§1.isMonad rhs - lemmaz : §1-fromMonad (§2-3.§1.toMonad m) ≡ m §2-3.§1.fmap (lemmaz i) = §2-3.§1.fmap m §2-3.§1.join (lemmaz i) = §2-3.§1.join m From fc7e5043596a4b93da48ad92ab9067a856c3e316 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frederik=20Hangh=C3=B8j=20Iversen?= Date: Wed, 23 May 2018 17:49:54 +0200 Subject: [PATCH 24/33] Correctly terminate appendix section --- doc/main.tex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/main.tex b/doc/main.tex index 8b5e7ff..2d5ad96 100644 --- a/doc/main.tex +++ b/doc/main.tex @@ -69,6 +69,6 @@ %% \input{sources.tex} %% \input{planning.tex} %% \input{halftime.tex} -%% \end{appendices} +\end{appendices} \printindex \end{document} From 2d0dfab12afb9ae0d24a77dcd8e3087592b48c03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frederik=20Hangh=C3=B8j=20Iversen?= Date: Wed, 23 May 2018 18:28:27 +0200 Subject: [PATCH 25/33] Remove some TODO-notes, add section on motifs --- doc/conclusion.tex | 38 +++++++++++++------------ doc/cubical.tex | 40 +++++++++++++++----------- doc/discussion.tex | 20 +++++++++++++ doc/implementation.tex | 64 ++++++++++++++++++++++++++---------------- doc/introduction.tex | 22 +++++++-------- 5 files changed, 114 insertions(+), 70 deletions(-) diff --git a/doc/conclusion.tex b/doc/conclusion.tex index 101a94f..a47ca3b 100644 --- a/doc/conclusion.tex +++ b/doc/conclusion.tex @@ -1,22 +1,24 @@ \chapter{Conclusion} -This thesis highlighted some issues with the standard inductive definition of -propositional equality used in Agda. Functional extensionality and univalence -are examples of two propositions not admissible in Intensional Type Theory -(ITT). This has a big impact on what is provable and the reusability of proofs. -This issue is overcome with an extension to Agda's type system called Cubical -Agda. With Cubical Agda both functional extensionality and univalence are -admissible. Cubical Agda is more expressive, but there are certain issues that -arise that are not present in standard Agda. For one thing ITT and standard Agda -enjoys Uniqueness of Identity Proofs (UIP). This is not the case in Cubical -Agda. In stead there exists a hierarchy of types with increasing -\nomen{homotopical structure}{homotopy levels}. It turns out to be useful to built the -formalization with this hierarchy in mind as it can simplify proofs -considerably. Another issue one must overcome in Cubical Agda is when a type has -a field whose type depends on a previous field. In this case paths between such -types will be heterogeneous paths. This problem is related to Cubical Agda not -having the K-rule \TODO{Not mentioned anywhere in the report}. In practice it -turns out to be considerably more difficult to work heterogeneous paths than -with homogeneous paths. The thesis demonstrated some techniques to overcome +This thesis highlighted some issues with the standard inductive +definition of propositional equality used in Agda. Functional +extensionality and univalence are examples of two propositions not +admissible in Intensional Type Theory (ITT). This has a big impact on +what is provable and the reusability of proofs. This issue is overcome +with an extension to Agda's type system called Cubical Agda. With +Cubical Agda both functional extensionality and univalence are +admissible. Cubical Agda is more expressive, but there are certain +issues that arise that are not present in standard Agda. For one thing +ITT and standard Agda enjoys Uniqueness of Identity Proofs (UIP). This +is not the case in Cubical Agda. In stead there exists a hierarchy of +types with increasing \nomen{homotopical structure}{homotopy levels}. +It turns out to be useful to built the formalization with this +hierarchy in mind as it can simplify proofs considerably. Another +issue one must overcome in Cubical Agda is when a type has a field +whose type depends on a previous field. In this case paths between +such types will be heterogeneous paths. This problem is related to +Cubical Agda not having the K-rule. In practice it turns out to be +considerably more difficult to work heterogeneous paths than with +homogeneous paths. The thesis demonstrated some techniques to overcome these difficulties, such as based path-induction. This thesis formalized some of the core concepts from category theory including; diff --git a/doc/cubical.tex b/doc/cubical.tex index a4a4c5f..e539d30 100644 --- a/doc/cubical.tex +++ b/doc/cubical.tex @@ -54,17 +54,18 @@ Judgmental equality in Cubical Agda is encapsulated with the type: \Path \tp (P \tp I → \MCU) → P\ 0 → P\ 1 → \MCU \end{equation} % -$I$ is a special data type (\TODO{that also has special computational properties - AFAIK}) called the index set. $I$ can be thought of simply as the interval on -the real numbers from $0$ to $1$. $P$ is a family of types over the index set -$I$. I will sometimes refer to $P$ as the \nomenindex{path space} of some path $p \tp -\Path\ P\ a\ b$. By this token $P\ 0$ then corresponds to the type at the -left-endpoint and $P\ 1$ as the type at the right-endpoint. The type is called -$\Path$ because it is connected with paths in homotopy theory. The intuition -behind this is that $\Path$ describes paths in $\MCU$ -- i.e.\ between types. For -a path $p$ for the point $p\ i$ the index $i$ describes how far along the path -one has moved. An inhabitant of $\Path\ P\ a_0\ a_1$ is a (dependent-) function, -$p$, from the index-space to the path space: +$I$ is a special data type called the index set. $I$ can be thought of +simply as the interval on the real numbers from $0$ to $1$. $P$ is a +family of types over the index set $I$. I will sometimes refer to $P$ +as the \nomenindex{path space} of some path $p \tp \Path\ P\ a\ b$. By +this token $P\ 0$ then corresponds to the type at the left-endpoint +and $P\ 1$ as the type at the right-endpoint. The type is called +$\Path$ because it is connected with paths in homotopy theory. The +intuition behind this is that $\Path$ describes paths in $\MCU$ -- +i.e.\ between types. For a path $p$ for the point $p\ i$ the index $i$ +describes how far along the path one has moved. An inhabitant of +$\Path\ P\ a_0\ a_1$ is a (dependent-) function, $p$, from the +index-space to the path space: % $$ p \tp \prod_{i \tp I} P\ i @@ -194,7 +195,7 @@ indeed both $\top$ and $\bot$ are propositions: The term $\varnothing$ is used here to denote an impossible pattern. It is a theorem that if a mere proposition $A$ is inhabited, then so is it contractible. If it is not inhabited it is equivalent to the empty-type (or false -proposition).\TODO{Cite!!} +proposition).\TODO{Cite} I will refer to a type $A \tp \MCU$ as a \emph{mere} proposition if I want to stress that we have $\isProp\ A$. @@ -242,11 +243,16 @@ Let $\left\Vert A \right\Vert = n$ denote that the level of $A$ is $n$. Proposition: For any homotopic level $n$ this is a mere proposition. % \section{A few lemmas} -Rather than getting into the nitty-gritty details of Agda I venture to take a -more ``combinator-based'' approach. That is, I will use theorems about paths -already that have already been formalized. Specifically the results come from -the Agda library \texttt{cubical} (\TODO{Cite}). I have used a handful of -results from this library as well as contributed a few lemmas myself.\footnote{The module \texttt{Cat.Prelude} lists the upstream dependencies. As well my contribution to \texttt{cubical} can be found in the git logs \TODO{Cite}.} +Rather than getting into the nitty-gritty details of Agda I venture to +take a more ``combinator-based'' approach. That is, I will use +theorems about paths already that have already been formalized. +Specifically the results come from the Agda library \texttt{cubical} +(\cite{cubical-demo}). I have used a handful of results from this +library as well as contributed a few lemmas myself.\footnote{The + module \texttt{Cat.Prelude} lists the upstream dependencies. As well + my contribution to \texttt{cubical} can be found in the git logs + which are available at + \hrefsymb{https://github.com/Saizan/cubical-demo}{\texttt{https://github.com/Saizan/cubical-demo}}.} These theorems are all purely related to homotopy theory and cubical Agda and as such not specific to the formalization of Category Theory. I will present a few diff --git a/doc/discussion.tex b/doc/discussion.tex index e021ff5..3dc101a 100644 --- a/doc/discussion.tex +++ b/doc/discussion.tex @@ -97,10 +97,25 @@ a significant impact on the complexity of these kinds of proofs. \TODO{Universe levels.} +\subsection{Motifs} +An oft-used technique in this development is using based path +induction to prove certain properties. One particular challenge that +arises when doing so is that Agda is not able to automatically infer +the family that one wants to do induction over. For instance in the +proof $\var{sym}\ (\var{sym}\ p) ≡ p$ from \ref{eq:sym-invol} the +family that we chose to do induction over was $D\ b'\ p' \defeq +\var{sym}\ (\var{sym}\ p') ≡ p'$. However, if one interactively tries +to give this hole, all the information that Agda can provide is that +one must provide an element of $𝒰$. Agda could be more helpful in this +context, perhaps even infer this family in some situations. In this +very simple example this is of course not a big problem, but there are +examples in the source code where this gets more involved. + \section{Future work} \subsection{Agda \texttt{Prop}} Jesper Cockx' work extending the universe-level-laws for Agda and the \texttt{Prop}-type. +\TODO{Do I want to include this?} \subsection{Compiling Cubical Agda} \label{sec:compiling-cubical-agda} @@ -117,3 +132,8 @@ library exposes could provide one particularly interesting case-study. \subsection{Higher inductive types} This library has not explored the usefulness of higher inductive types in the context of Category Theory. + +\subsection{Initiality conjecture} +A fellow student here at Chalmers, Andreas Källberg, is currently +working on proving the initiality conjecture\TODO{Citation}. He will +be using this library to do so. diff --git a/doc/implementation.tex b/doc/implementation.tex index 0a26bd0..c7604e3 100644 --- a/doc/implementation.tex +++ b/doc/implementation.tex @@ -277,16 +277,19 @@ $i$ becomes the triple: \end{aligned} \end{equation} % -I have found this to be a general pattern when proving things in homotopy type -theory, namely that you have to wrap and unwrap equalities at different levels. -It is worth noting that proving this theorem with the regular inductive equality -type would already not be possible, since we at least need extensionality (the -projections are all $\prod$-types). Assuming we had functional extensionality -available to us as an axiom, we would use functional extensionality \TODO{in -reverse?} to retrieve the equalities in $a$ and $b$, pattern-match on them to -see that they are both $\refl$ and then close the proof with $\refl$. -Of course this theorem is not so interesting in the setting of ITT since we know -a priori that equality proofs are unique. +I have found this to be a general pattern when proving things in +homotopy type theory, namely that you have to wrap and unwrap +equalities at different levels. It is worth noting that proving this +theorem with the regular inductive equality type would already not be +possible, since we at least need functional +extensionality\index{functional extensionality} (the projections are +all $\prod$-types). Assuming we had functional extensionality +available to us as an axiom, we would use functional extensionality +\TODO{in reverse?} to retrieve the equalities in $a$ and $b$, +pattern-match on them to see that they are both $\refl$ and then close +the proof with $\refl$. Of course this theorem is not so interesting +in the setting of ITT since we know a priori that equality proofs are +unique. The situation is a bit more complicated when we have a dependent type. For instance, when we want to show that $\IsCategory$ is a mere @@ -326,8 +329,8 @@ $$ And this finishes the proof that being-a-category is a mere proposition (\ref{eq:propIsPreCategory}). -When we have a proper category we can make precise the notion of ``identifying -isomorphic types'' \TODO{cite Awodey here}. That is, we can construct the +When we have a proper category we can make precise the notion of +``identifying isomorphic types''. That is, we can construct the function: % $$ @@ -345,7 +348,11 @@ terminal objects are propositional: It follows from the usual observation that any two terminal objects are isomorphic - and since categories are univalent, so are they equal. The proof is omitted here, but the curious reader can check the implementation for the -details. \TODO{The proof is a bit fun, should I include it?} +details. It is in the module: +% +\begin{center} +\sourcelink{Cat.Category} +\end{center} \section{Equivalences} \label{sec:equiv} @@ -733,7 +740,7 @@ $x \equiv y$ and $\fst\ x \equiv \fst\ y$: \end{aligned} \end{equation*} % -\TODO{Is it confusing that I use point-free style here?} Here $\var{lemSig}$ is +\TODO{Is it confusing that I use point-free style here?}Here $\var{lemSig}$ is a lemma that says that if the second component of a pair is a proposition, it suffices to give a path between its first components to construct an equality of the two pairs: @@ -744,15 +751,18 @@ the two pairs: \left( \fst\ u \equiv \fst\ v \right) \to u \equiv v \end{align*} % -The proof that these are indeed inverses has been omitted. \TODO{Do I really - want to omit it?}\QED +The proof that these are indeed inverses has been omitted. The details +can be found in the module: +\begin{center} +\sourcelink{Cat.Categories.Sets} +\end{center} -Now to prove \ref{eq:equivSig}: Let $e \tp \prod_{a \tp A} \left( P\ a \simeq -Q\ a \right)$ be given. To prove the equivalence, it suffices to give an -isomorphism between $\sum_{a \tp A} P\ a$ and $\sum_{a \tp A} Q\ a$, but since -they have identical first components it suffices to give an isomorphism between -$P\ a$ and $Q\ a$ for all $a \tp A$. This is exactly what we can get from -the equivalence $e$.\QED +Now to prove \ref{eq:equivSig}: Let $e \tp \prod_{a \tp A} \left( P\ a +\simeq Q\ a \right)$ be given. To prove the equivalence, it suffices +to give an isomorphism between $\sum_{a \tp A} P\ a$ and $\sum_{a \tp + A} Q\ a$, but since they have identical first components it suffices +to give an isomorphism between $P\ a$ and $Q\ a$ for all $a \tp A$. +This is exactly what we can get from the equivalence $e$.\QED Lastly we prove \ref{eq:equivIso}. Let $f \tp A \to B$ be given. For the maps we choose: @@ -1050,7 +1060,10 @@ $b_0, b_1$ corresponds to a pair of paths between $a_0,b_0$ and $a_1,b_1$ (check the implementation for the details). \emph{Proposition} \ref{eq:univ-1} is isomorphic to \ref{eq:univ-2}: -\TODO{Super complicated} +This proof of this has been omitted but can be found in the module: +\begin{center} +\sourcelink{Cat.Categories.Span} +\end{center} \emph{Proposition} \ref{eq:univ-2} is isomorphic to \ref{eq:univ-3}: For this I will show two corollaries of \ref{eq:coeCod}: For an isomorphism $(\iota, @@ -1067,7 +1080,10 @@ f & \equiv g \lll \iota \\ g & \equiv f \lll \inv{\iota} \end{align} % -Proof: \TODO{\ldots} +The proof is omitted but can be found in the module: +\begin{center} +\sourcelink{Cat.Category} +\end{center} Now we can prove the equivalence in the following way: Given $(f, \inv{f}, \var{inv}_f) \tp X \cong Y$ and two heterogeneous paths diff --git a/doc/introduction.tex b/doc/introduction.tex index 853da02..59c1037 100644 --- a/doc/introduction.tex +++ b/doc/introduction.tex @@ -207,14 +207,13 @@ implementations of category theory in Agda: % The contribution of this thesis is to explore how working in a cubical setting will make it possible to prove more things and to reuse proofs and to try and -compare some aspects of this formalization with the existing ones.\TODO{How can - I live up to this?} +compare some aspects of this formalization with the existing ones. There are alternative approaches to working in a cubical setting where one can still have univalence and functional extensionality. One option is to postulate these as axioms. This approach, however, has other shortcomings, e.g. you lose \nomenindex{canonicity} -(\TODO{Pageno!} \cite{huber-2016}). +(\cite[p. 3]{huber-2016}). Another approach is to use the \emph{setoid interpretation} of type theory (\cite{hofmann-1995,huber-2016}). With this approach one works @@ -227,16 +226,17 @@ relation a priori. So this must be verified manually by the developer. Furthermore, functions between different setoids must be shown to be setoid homomorphism, that is; they preserve the relation. -This approach has other drawbacks; it does not satisfy -all propositional equalities of type theory (\TODO{Citation needed}), is -cumbersome to work with in practice (\cite[p. 4]{huber-2016}) and makes -equational proofs less reusable since equational proofs $a \sim_{X} b$ are -inherently `local' to the extensional set $(X , \sim)$. +This approach has other drawbacks; it does not satisfy all +propositional equalities of type theory a priori. That is, the +developer must manually show that e.g.\ the relation is a congruence. +Equational proofs $a \sim_{X} b$ are in some sense `local' to the +extensional set $(X , \sim)$. To e.g.\ prove that $x ∼ y → f\ x ∼ +f\ y$ for some function $f \tp A → B$ between two extensional sets $A$ +and $B$ it must be shown that $f$ is a groupoid homomorphism. This +makes it very cumbersome to work with in practice (\cite[p. + 4]{huber-2016}). \section{Conventions} -\TODO{Talk a bit about terminology. Find a good place to stuff this little - section.} - In the remainder of this paper I will use the term \nomenindex{Type} to describe -- well, types. Thereby diverging from the notation in Agda where the keyword From 326951d826a158d2e0b3a21381790a3182fa145e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frederik=20Hangh=C3=B8j=20Iversen?= Date: Thu, 24 May 2018 15:57:30 +0200 Subject: [PATCH 26/33] Put in brackets for readability --- doc/implementation.tex | 49 +++++++++++++++++++++++++----------------- doc/packages.tex | 4 ++-- 2 files changed, 31 insertions(+), 22 deletions(-) diff --git a/doc/implementation.tex b/doc/implementation.tex index c7604e3..69cba0c 100644 --- a/doc/implementation.tex +++ b/doc/implementation.tex @@ -109,7 +109,7 @@ definitions: If we let $p$ be a witness to the identity law, which formally is: \label{eq:identity} \var{IsIdentity} \defeq \prod_{A\ B \tp \Object} \prod_{f \tp \Arrow\ A\ B} - \id \lll f \equiv f \x f \lll \id \equiv f + \left(\id \lll f \equiv f\right) \x \left(f \lll \id \equiv f\right) \end{equation} % Then we can construct the identity isomorphism $\idIso \tp \identity, @@ -160,8 +160,13 @@ And laws: %% \tag{associativity} h \lll (g \lll f) ≡ (h \lll g) \lll f \\ %% \tag{identity} -\identity \lll f ≡ f \x +\left( +\identity \lll f ≡ f +\right) +\x +\left( f \lll \identity ≡ f +\right) \\ \label{eq:arrows-are-sets} %% \tag{arrows are sets} @@ -201,7 +206,7 @@ So the proof goes like this: We `eliminate' the 3 function abstractions by applying $\propPi$ three times. So our proof obligation becomes: % $$ -\isProp\ \left( \id \comp f \equiv f \x f \comp \id \equiv f \right) +\isProp\ \left( \left( \id \comp f \equiv f \right) \x \left( f \comp \id \equiv f \right) \right) $$ % Then we eliminate the (non-dependent) sigma-type by applying $\propSig$ giving @@ -360,7 +365,7 @@ The usual notion of a function $f \tp A \to B$ having an inverses is: % \begin{equation} \label{eq:isomorphism} -\sum_{g \tp B \to A} f \comp g \equiv \identity \x g \comp f \equiv \identity +\sum_{g \tp B \to A} \left( f \comp g \equiv \identity \right) \x \left( g \comp f \equiv \identity \right) \end{equation} % This is defined in \cite[p. 129]{hott-2013} where it is referred to as the a @@ -608,7 +613,7 @@ An inhabitant of $A \approxeq B$ is simply an arrow $f \tp \Arrow\ A\ B$ and its inverse $g \tp \Arrow\ B\ A$. In the opposite category $g$ will play the role of the isomorphism and $f$ will be the inverse. Similarly we can go in the opposite direction. I name these maps $\shufflef \tp (A \approxeq -B) \to (A \wideoverbar{\approxeq} B)$ and $\shuffle^{-1} \tp (A +B) \to (A \wideoverbar{\approxeq} B)$ and $\shufflef^{-1} \tp (A \wideoverbar{\approxeq} B) \to (A \approxeq B)$ respectively. As the inverse of $\wideoverbar{\idToIso}$ I will pick $\wideoverbar{\isoToId} @@ -648,8 +653,8 @@ $$ $$ % As we have seen the laws in $\left(\bC^{\var{Op}}\right)^{\var{Op}}$ get quite -involved.\footnote{We have not even seen the full story because we have used - this `interface' for equivalences.} Luckily since being-a-category is a mere +involved\footnote{We have not even seen the full story because we have used + this `interface' for equivalences.}. Luckily since being-a-category is a mere proposition, we need not concern ourselves with this bit when proving the above. We can use the equality principle for categories that let us prove an equality just by giving an equality on the data-part. So, given a category $\bC$ all we @@ -798,13 +803,13 @@ inverse to $f$. The path $p$ is inhabited by: % \begin{align*} x - & \equiv x \comp \identity \\ + & = x \comp \identity \\ & \equiv x \comp (f \comp y) && \text{$y$ is an inverse to $f$} \\ & \equiv (x \comp f) \comp y \\ & \equiv \identity \comp y && \text{$x$ is an inverse to $f$} \\ - & \equiv y + & = y \end{align*} % For the other (dependent) path we can prove that being-an-inverse-of is a @@ -1061,10 +1066,11 @@ the implementation for the details). \emph{Proposition} \ref{eq:univ-1} is isomorphic to \ref{eq:univ-2}: This proof of this has been omitted but can be found in the module: -\begin{center} +% +\begin{center}% \sourcelink{Cat.Categories.Span} \end{center} - +% \emph{Proposition} \ref{eq:univ-2} is isomorphic to \ref{eq:univ-3}: For this I will show two corollaries of \ref{eq:coeCod}: For an isomorphism $(\iota, \inv{\iota}, \var{inv}) \tp A \cong B$, arrows $f \tp \Arrow\ A\ X$, $g \tp @@ -1108,7 +1114,7 @@ To show that this choice fits the bill I must now verify that it satisfies \ref{eq:pairArrowLaw}, which in this case becomes: % \begin{align} -y_{\mathcal{A}} \lll f ≡ x_{\mathcal{A}} × y_{\mathcal{B}} \lll f ≡ x_{\mathcal{B}} +(y_{\mathcal{A}} \lll f ≡ x_{\mathcal{A}}) × (y_{\mathcal{B}} \lll f ≡ x_{\mathcal{B}}) \end{align} % Which, since $f$ is an isomorphism and $p_{\mathcal{A}}$ (resp.\ $p_{\mathcal{B}}$) @@ -1217,10 +1223,11 @@ indeed a product. That is, for an object $Y$ and two arrows $y_𝒜 \tp % \begin{align} \label{eq:pairCondRev} -\begin{split} - x_𝒜 \lll f & ≡ y_𝒜 \\ - x_ℬ \lll f & ≡ y_ℬ -\end{split} +%% \begin{split} + ( x_𝒜 \lll f ≡ y_𝒜 ) + \x + ( x_ℬ \lll f ≡ y_ℬ ) +%% \end{split} \end{align} % Since $X, x_𝒜, x_ℬ$ is a terminal object there is a \emph{unique} arrow from @@ -1250,8 +1257,9 @@ of proofs: Here $\Phi$ is given as: $$ \prod_{f \tp \Arrow\ Y\ X} - x_𝒜 \lll f ≡ y_𝒜 -× x_ℬ \lll f ≡ y_ℬ + ( x_𝒜 \lll f ≡ y_𝒜 ) + × + ( x_ℬ \lll f ≡ y_ℬ ) $$ % $p$ follows from the universal property of $y_𝒜 \x y_ℬ$. For the latter we will @@ -1260,8 +1268,9 @@ more general result: % $$ \prod_{f \tp \Arrow\ Y\ X} \isProp\ ( - x_𝒜 \lll f ≡ y_𝒜 -× x_ℬ \lll f ≡ y_ℬ +( x_𝒜 \lll f ≡ y_𝒜 ) +× +( x_ℬ \lll f ≡ y_ℬ ) ) $$ % diff --git a/doc/packages.tex b/doc/packages.tex index 1b434ba..ba2ccba 100644 --- a/doc/packages.tex +++ b/doc/packages.tex @@ -90,8 +90,8 @@ \newunicodechar{⟨}{\textfallback{⟨}} \newunicodechar{⟩}{\textfallback{⟩}} \newunicodechar{∎}{\textfallback{∎}} -\newunicodechar{𝒜}{\textfallback{?}} -\newunicodechar{ℬ}{\textfallback{?}} +%% \newunicodechar{𝒜}{\textfallback{𝒜}} +%% \newunicodechar{ℬ}{\textfallback{ℬ}} %% \newunicodechar{≊}{\textfallback{≊}} \makeatletter \newcommand*{\rom}[1]{\expandafter\@slowroman\romannumeral #1@} From 636b5f3e27fdddee12df1dc815320b978a6fa7a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frederik=20Hangh=C3=B8j=20Iversen?= Date: Sat, 26 May 2018 01:15:57 +0200 Subject: [PATCH 27/33] Makefile uses included libraries --- Makefile | 2 +- libs/agda-stdlib | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 9d0744c..bec101b 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ build: src/**.agda - agda src/Cat.agda + agda --library-file ./libraries src/Cat.agda clean: find src -name "*.agdai" -type f -delete diff --git a/libs/agda-stdlib b/libs/agda-stdlib index 55ad461..2096269 160000 --- a/libs/agda-stdlib +++ b/libs/agda-stdlib @@ -1 +1 @@ -Subproject commit 55ad461aa4fc6cf22e97812b7ff8128b3c7a902c +Subproject commit 209626953d56294e9bd3d8892eda43b844b0edf9 From 1f750e227564e00597e7d82a6d910ce5754d0d1a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frederik=20Hangh=C3=B8j=20Iversen?= Date: Mon, 28 May 2018 17:32:56 +0200 Subject: [PATCH 28/33] Erratta --- doc/abstract.tex | 19 ++- doc/acknowledgements.tex | 13 ++ doc/appendix/abstract-funext.tex | 2 +- doc/chalmerstitle.sty | 3 +- doc/conclusion.tex | 72 ++++---- doc/cubical.tex | 281 ++++++++++++++++--------------- doc/discussion.tex | 13 +- doc/implementation.tex | 205 +++++++++++----------- doc/introduction.tex | 229 ++++++++++++------------- doc/macros.tex | 1 + doc/main.tex | 2 + doc/packages.tex | 5 +- doc/presentation.tex | 206 +++++++++++----------- 13 files changed, 549 insertions(+), 502 deletions(-) create mode 100644 doc/acknowledgements.tex diff --git a/doc/abstract.tex b/doc/abstract.tex index e2bb834..17b3853 100644 --- a/doc/abstract.tex +++ b/doc/abstract.tex @@ -1,21 +1,22 @@ \chapter*{Abstract} The usual notion of propositional equality in intensional type-theory is restrictive. For instance it does not admit functional -extensionality or univalence. This poses a severe limitation on both +extensionality nor univalence. This poses a severe limitation on both what is \emph{provable} and the \emph{re-usability} of proofs. Recent -developments have, however, resulted in cubical type theory which +developments have however resulted in cubical type theory which permits a constructive proof of these two important notions. The programming language Agda has been extended with capabilities for working in such a cubical setting. This thesis will explore the usefulness of this extension in the context of category theory. -The thesis will motivate and explain why propositional equality in -cubical Agda is more expressive than in standard Agda. Alternative -approaches to Cubical Agda will be presented and their pros and cons -will be explained. It will emphasize why it is useful to have a -constructive interpretation of univalence. As an example of this two -formulations of monads will be presented: Namely monads in the -monoidal form and monads in the Kleisli form. +The thesis will motivate the need for univalence and explain why +propositional equality in cubical Agda is more expressive than in +standard Agda. Alternative approaches to Cubical Agda will be +presented and their pros and cons will be explained. As an example of +the application of univalence two formulations of monads will be +presented: Namely monads in the monoidal form and monads in the +Kleisli form and under the univalent interpretation it will be shown +how these are equal. Finally the thesis will explain the challenges that a developer will face when working with cubical Agda and give some techniques to diff --git a/doc/acknowledgements.tex b/doc/acknowledgements.tex new file mode 100644 index 0000000..e4c45e3 --- /dev/null +++ b/doc/acknowledgements.tex @@ -0,0 +1,13 @@ +\chapter*{Acknowledgements} +I would like to thank my supervisor Thierry Coquand for giving me a +chance to work on this interesting topic. I would also like to thank +Andrea Vezzosi for some very long and very insightful meetings during +the project. It is fascinating and almost uncanny how quickly Andrea +can conjure up various proofs. I also want to recognize the support +of Knud Højgaards Fond who graciously sponsored me with a 20.000 DKK +scholarship which helped toward sponsoring the two years I have spent +studying abroad. I would also like to give a warm thanks to my fellow +students Pierre Kraft and Nachiappan Villiappan who have made the time +spent working on the thesis way more enjoyable. Lastly I would like to +give a special thanks to Valentina Méndez who have been a great moral +support throughout the whole process. diff --git a/doc/appendix/abstract-funext.tex b/doc/appendix/abstract-funext.tex index dafb81f..918990c 100644 --- a/doc/appendix/abstract-funext.tex +++ b/doc/appendix/abstract-funext.tex @@ -1,4 +1,4 @@ -\chapter{Abstract functional extensionality} +\chapter{Non-reducing functional extensionality} \label{app:abstract-funext} In two places in my formalization was the computational behaviours of functional extensionality used. The reduction behaviour can be diff --git a/doc/chalmerstitle.sty b/doc/chalmerstitle.sty index 90cd06c..908e13d 100644 --- a/doc/chalmerstitle.sty +++ b/doc/chalmerstitle.sty @@ -46,7 +46,8 @@ {\Huge\@title}\\[.5cm] {\Large A formalization of category theory in Cubical Agda}\\[6cm] \begin{center} -\includegraphics[width=\linewidth,keepaspectratio]{isomorphism.png} +\includegraphics[width=\linewidth,keepaspectratio]{isomorphism.pdf} +%% \includepdf{isomorphism.pdf} \end{center} % Cover text \vfill diff --git a/doc/conclusion.tex b/doc/conclusion.tex index a47ca3b..c4d0d10 100644 --- a/doc/conclusion.tex +++ b/doc/conclusion.tex @@ -8,40 +8,46 @@ with an extension to Agda's type system called Cubical Agda. With Cubical Agda both functional extensionality and univalence are admissible. Cubical Agda is more expressive, but there are certain issues that arise that are not present in standard Agda. For one thing -ITT and standard Agda enjoys Uniqueness of Identity Proofs (UIP). This -is not the case in Cubical Agda. In stead there exists a hierarchy of -types with increasing \nomen{homotopical structure}{homotopy levels}. -It turns out to be useful to built the formalization with this -hierarchy in mind as it can simplify proofs considerably. Another -issue one must overcome in Cubical Agda is when a type has a field -whose type depends on a previous field. In this case paths between -such types will be heterogeneous paths. This problem is related to -Cubical Agda not having the K-rule. In practice it turns out to be -considerably more difficult to work heterogeneous paths than with -homogeneous paths. The thesis demonstrated some techniques to overcome -these difficulties, such as based path-induction. +Agda enjoys Uniqueness of Identity Proofs (UIP) though a flag exists +to turn this off, which is the case in Cubical Agda. In stead +there exists a hierarchy of types with increasing \nomen{homotopical + structure}{homotopy levels}. It turns out to be useful to built the +formalization with this hierarchy in mind as it can simplify proofs +considerably. Another issue one must overcome in Cubical Agda is when +a type has a field whose type depends on a previous field. In this +case paths between such types will be heterogeneous paths. This +problem is related to Cubical Agda not having the K-rule. In practice +it turns out to be considerably more difficult to work heterogeneous +paths than with homogeneous paths. The thesis demonstrated some +techniques to overcome these difficulties, such as based +path-induction. -This thesis formalized some of the core concepts from category theory including; -categories, functors, products, exponentials, Cartesian closed categories, -natural transformations, the yoneda embedding, monads and more. Category theory -is an interesting case-study for the application of Cubical Agda for two reasons -in particular: Because category theory is the study of abstract algebra of -functions, meaning that functional extensionality is particularly relevant. -Another reason is that in category theory it is commonplace to identify -isomorphic structures and univalence allows for making this notion precise. This -thesis also demonstrated another technique that is common in category theory; -namely to define categories to prove properties of other structures. -Specifically a category was defined to demonstrate that any two product objects -in a category are isomorphic. Furthermore the thesis showed two formulations of -monads and proved that they indeed are equivalent: Namely monads in the -monoidal- and Kleisli- form. The monoidal formulation is more typical to -category theoretic formulations and the Kleisli formulation will be more -familiar to functional programmers. In the formulation we also saw how paths can -be used to extract functions. A path between two types induce an isomorphism -between the two types. This e.g. permits developers to write a monad instance -for a given type using the Kleisli formulation. By transporting along the path -between the monoidal- and Kleisli- formulation one can reuse all the operations -and results shown for monoidal- monads in the context of kleisli monads. +This thesis formalized some of the core concepts from category theory +including; categories, functors, products, exponentials, Cartesian +closed categories, natural transformations, the yoneda embedding, +monads and more. Category theory is an interesting case-study for the +application of Cubical Agda for two reasons in particular: Because +category theory is the study of abstract algebra of functions, meaning +that functional extensionality is particularly relevant. Another +reason is that in category theory it is commonplace to identify +isomorphic structures and univalence allows for making this notion +precise. This thesis also demonstrated another technique that is +common in category theory; namely to define categories to prove +properties of other structures. Specifically a category was defined +to demonstrate that any two product objects in a category are +isomorphic. Furthermore the thesis showed two formulations of monads +and proved that they indeed are equivalent: Namely monads in the +monoidal- and Kleisli- form. The monoidal formulation is more typical +to category theoretic formulations and the Kleisli formulation will be +more familiar to functional programmers. It would have been very +difficult to make a similar proof with setoids. In the formulation we +also saw how paths can be used to extract functions. A path between +two types induce an isomorphism between the two types. This +e.g. permits developers to write a monad instance for a given type +using the Kleisli formulation. By transporting along the path between +the monoidal- and Kleisli- formulation one can reuse all the +operations and results shown for monoidal- monads in the context of +kleisli monads. %% %% problem with inductive type %% overcome with cubical diff --git a/doc/cubical.tex b/doc/cubical.tex index e539d30..40d2beb 100644 --- a/doc/cubical.tex +++ b/doc/cubical.tex @@ -1,29 +1,31 @@ \chapter{Cubical Agda} \section{Propositional equality} -Judgmental equality in Agda is a feature of the type system. Its something that -can be checked automatically by the type checker: In the example from the -introduction $n + 0$ can be judged to be equal to $n$ simply by expanding the -definition of $+$. +Judgmental equality in Agda is a feature of the type system. It is +something that can be checked automatically by the type checker: In +the example from the introduction $n + 0$ can be judged to be equal to +$n$ simply by expanding the definition of $+$. -On the other hand, propositional equality is something defined within the -language itself. Propositional equality cannot be derived automatically. The -normal definition of judgmental equality is an inductive data type. Cubical Agda -discards this type in favor of a new primitives that has certain computational -properties exclusive to it. +On the other hand, propositional equality is something defined within +the language itself. Propositional equality cannot be derived +automatically. The normal definition of judgmental equality is an +inductive data type. Cubical Agda discards this type in favor of some +new primitives. -The source code can be browsed online and is linked in the beginning -of \S\ref{ch:implementation}. +Most of the source code related with this section is implemented in +\cite{cubical-demo} it can be browsed in hyperlinked and syntax +highlighted HTML online. The links can be found in the beginning of +section \S\ref{ch:implementation}. \subsection{The equality type} -The usual notion of judgmental equality says that given a type $A \tp \MCU$ and -two points of $A$; $a_0, a_1 \tp A$ we can form the type: +The usual notion of judgmental equality says that given a type $A \tp +\MCU$ and two points hereof $a_0, a_1 \tp A$ we can form the type: % \begin{align} a_0 \equiv a_1 \tp \MCU \end{align} % -In Agda this is defined as an inductive data type with the single constructor -for any $a \tp A$: +In Agda this is defined as an inductive data type with the single +constructor $\refl$ that for any $a \tp A$ gives: % \begin{align} \refl \tp a \equiv a @@ -37,8 +39,8 @@ for equating points of different types. In this case given two types $A, B \tp a \cong b \tp \MCU \end{align} % -This is likewise defined as an inductive data type with a single constructors -for any $a \tp A$: +This likewise has the single constructor $\refl$ that for any $a \tp +A$ gives: % \begin{align} \refl \tp a \cong a @@ -51,28 +53,28 @@ heterogeneous paths respectively. Judgmental equality in Cubical Agda is encapsulated with the type: % \begin{equation} -\Path \tp (P \tp I → \MCU) → P\ 0 → P\ 1 → \MCU +\Path \tp (P \tp \I → \MCU) → P\ 0 → P\ 1 → \MCU \end{equation} % -$I$ is a special data type called the index set. $I$ can be thought of -simply as the interval on the real numbers from $0$ to $1$. $P$ is a -family of types over the index set $I$. I will sometimes refer to $P$ -as the \nomenindex{path space} of some path $p \tp \Path\ P\ a\ b$. By -this token $P\ 0$ then corresponds to the type at the left-endpoint -and $P\ 1$ as the type at the right-endpoint. The type is called -$\Path$ because it is connected with paths in homotopy theory. The -intuition behind this is that $\Path$ describes paths in $\MCU$ -- -i.e.\ between types. For a path $p$ for the point $p\ i$ the index $i$ -describes how far along the path one has moved. An inhabitant of -$\Path\ P\ a_0\ a_1$ is a (dependent-) function, $p$, from the -index-space to the path space: +The special type $\I$ is called the index set. The index set can be +thought of simply as the interval on the real numbers from $0$ to $1$ +(both inclusive). The family $P$ over $\I$ will be referred to as the +\nomenindex{path space} given some path $p \tp \Path\ P\ a\ b$. By +that token $P\ 0$ corresponds to the type at the left endpoint of $p$. +Likewise $P\ 1$ is the type at the right endpoint. The type is called +$\Path$ because the idea has roots in homotopy theory. The intuition +is that $\Path$ describes\linebreak[1] paths in $\MCU$. I.e.\ paths +between types. For a path $p$ the expression $p\ i$ can be thought of +as a \emph{point} on this path. The index $i$ describes how far along +the path one has moved. An inhabitant of $\Path\ P\ a_0\ a_1$ is a +(dependent) function from the index set to the path space: % $$ -p \tp \prod_{i \tp I} P\ i +p \tp \prod_{i \tp \I} P\ i $$ % -Which must satisfy being judgmentally equal to $a_0$ (respectively $a_1$) at the -endpoints. I.e.: +Which must satisfy being judgmentally equal to $a_0$ at the +left endpoint and equal to $a_1$ at the other end. I.e.: % \begin{align*} p\ 0 & = a_0 \\ @@ -80,80 +82,77 @@ endpoints. I.e.: \end{align*} % The notion of \nomenindex{homogeneous equalities} is recovered when $P$ does not -depend on its argument. That is for $A \tp \MCU$, $a_0, a_1 \tp A$ the +depend on its argument. That is for $A \tp \MCU$ and $a_0, a_1 \tp A$ the homogenous equality between $a_0$ and $a_1$ is the type: % $$ -a_0 \equiv a_1 \defeq \Path\ (\lambda i \to A)\ a_0\ a_1 +a_0 \equiv a_1 \defeq \Path\ (\lambda\;i \to A)\ a_0\ a_1 $$ % -I will generally prefer to use the notation -$a \equiv b$ when talking about non-dependent paths and use the notation -$\Path\ (\lambda i \to P\ i)\ a\ b$ when the path space is of particular -interest. +I will generally prefer to use the notation $a \equiv b$ when talking +about non-dependent paths and use the notation $\Path\ (\lambda\; i +\to P\ i)\ a\ b$ when the path space is of particular interest. With this definition we can also recover reflexivity. That is, for any $A \tp \MCU$ and $a \tp A$: % \begin{equation} \begin{aligned} -\refl & \tp \Path (\lambda i \to A)\ a\ a \\ -\refl & \defeq \lambda i \to a +\refl & \tp a \equiv a \\ +\refl & \defeq \lambda\; i \to a \end{aligned} \end{equation} % -Here the path space is $P \defeq \lambda i \to A$ and it satsifies $P\ i = A$ -definitionally. So to inhabit it, is to give a path $I \to A$ which is -judgmentally $a$ at either endpoint. This is satisfied by the constant path; -i.e.\ the path that stays at $a$ at any index $i$. +Here the path space is $P \defeq \lambda\; i \to A$ and it satsifies +$P\ i = A$ definitionally. So to inhabit it, is to give a path $\I \to +A$ which is judgmentally $a$ at either endpoint. This is satisfied by +the constant path; i.e.\ the path that is constantly $a$ at any index +$i \tp \I$. -It is also surpisingly easy to show functional extensionality with which we can -construct a path between $f$ and $g$ -- the functions defined in the -introduction (section \S\ref{sec:functional-extensionality}). Functional -extensionality is the proposition, given a type $A \tp \MCU$, a family of types -$B \tp A \to \MCU$ and functions $f, g \tp \prod_{a \tp A} B\ a$: +It is also surprisingly easy to show functional extensionality. +Functional extensionality is the proposition that given a type $A \tp +\MCU$, a family of types $B \tp A \to \MCU$ and functions $f, g \tp +\prod_{a \tp A} B\ a$ gives: % \begin{equation} \label{eq:funExt} -\funExt \tp \prod_{a \tp A} f\ a \equiv g\ a \to f \equiv g +\funExt \tp \left(\prod_{a \tp A} f\ a \equiv g\ a \right) \to f \equiv g \end{equation} % -%% p = λ i a → p a i -So given $p \tp \prod_{a \tp A} f\ a \equiv g\ a$ we must give a path $f \equiv -g$. That is a function $I \to \prod_{a \tp A} B\ a$. So let $i \tp I$ be given. +%% p = λ\; i a → p a i +So given $η \tp \prod_{a \tp A} f\ a \equiv g\ a$ we must give a path $f \equiv +g$. That is a function $\I \to \prod_{a \tp A} B\ a$. So let $i \tp \I$ be given. We must now give an expression $\phi \tp \prod_{a \tp A} B\ a$ satisfying $\phi\ 0 \equiv f\ a$ and $\phi\ 1 \equiv g\ a$. This neccesitates that the expression must be a lambda-abstraction, so let $a \tp A$ be given. Now we can -apply $a$ to $p$ and get the path $p\ a \tp f\ a \equiv g\ a$. And this exactly -satisfied the conditions for $\phi$. In conclustion \ref{eq:funExt} is inhabited +apply $a$ to $η$ and get the path $η\ a \tp f\ a \equiv g\ a$. And this exactly +satisfies the conditions for $\phi$. In conclustion \ref{eq:funExt} is inhabited by the term: % -\begin{equation} -\label{eq:funExt} -\funExt\ p \defeq λ i\ a → p\ a\ i -\end{equation} +\begin{equation*} +\funExt\ η \defeq λ\; i\ a → η\ a\ i +\end{equation*} % -With this we can now prove the desired equality $f \equiv g$ from section -\S\ref{sec:functional-extensionality}: +With $\funExt$ in place we can now construct a path between +$\var{zeroLeft}$ and $\var{zeroRight}$ -- the functions defined in the +introduction \S\ref{sec:functional-extensionality}: % \begin{align*} - p & \tp f \equiv g \\ - p & \defeq \funExt\ \phi + p & \tp \var{zeroLeft} \equiv \var{zeroRight} \\ + p & \defeq \funExt\ \var{zrn} \end{align*} % -Here $\phi \tp \prod_{n \tp \bN} \var{zeroLeft}\ n \equiv -\var{zeroRight} n$. Paths have some other important properties, but -they are not the focus of this thesis. \TODO{Refer the reader - somewhere for more info.} +Here $\var{zrn}$ is the proof from \ref{eq:zrn}. % \section{Homotopy levels} -In ITT all equality proofs are identical (in a closed context). This means that, -in some sense, any two inhabitants of $a \equiv b$ are ``equally good'' -- they -do not have any interesting structure. This is referred to as Uniqueness of -Identity Proofs (UIP). Unfortunately it is not possible to have a type theory -with both univalence and UIP. In stead we have a hierarchy of types with an -increasing amount of homotopic structure. At the bottom of this hierarchy we -have the set of contractible types: +In ITT all equality proofs are identical (in a closed context). This +means that, in some sense, any two inhabitants of $a \equiv b$ are +``equally good''. They do not have any interesting structure. This is +referred to as Uniqueness of Identity Proofs (UIP). Unfortunately it +is not possible to have a type theory with both univalence and UIP. In +stead in cubical Agda we have a hierarchy of types with an increasing +amount of homotopic structure. At the bottom of this hierarchy is the +set of contractible types: % \begin{equation} \begin{aligned} @@ -168,8 +167,9 @@ The first component of $\isContr\ A$ is called ``the center of contraction''. Under the propositions-as-types interpretation of type theory $\isContr\ A$ can be thought of as ``the true proposition $A$''. And indeed $\top$ is contractible: +% \begin{equation*} -\var{tt} , \lambda x \to \refl \tp \isContr\ \top +(\var{tt} , \lambda\; x \to \refl) \tp \isContr\ \top \end{equation*} % It is a theorem that if a type is contractible, then it is isomorphic to the @@ -188,19 +188,19 @@ One can think of $\isProp\ A$ as the set of true and false propositions. And indeed both $\top$ and $\bot$ are propositions: % \begin{align*} -λ \var{tt}\ \var{tt} → refl & \tp \isProp\ ⊤ \\ -λ\varnothing\ \varnothing & \tp \isProp\ ⊥ +(λ\; \var{tt}, \var{tt} → refl) & \tp \isProp\ ⊤ \\ +λ\;\varnothing\ \varnothing & \tp \isProp\ ⊥ \end{align*} % The term $\varnothing$ is used here to denote an impossible pattern. It is a theorem that if a mere proposition $A$ is inhabited, then so is it contractible. If it is not inhabited it is equivalent to the empty-type (or false -proposition).\TODO{Cite} +proposition). -I will refer to a type $A \tp \MCU$ as a \emph{mere} proposition if I want to +I will refer to a type $A \tp \MCU$ as a \emph{mere proposition} if I want to stress that we have $\isProp\ A$. -Then comes the set of homotopical sets: +The next step in the hierarchy is the set of homotopical sets: % \begin{equation} \begin{aligned} @@ -209,13 +209,14 @@ Then comes the set of homotopical sets: \end{aligned} \end{equation} % -I will not give an example of a set at this point. It turns out that proving -e.g.\ $\isProp\ \bN$ is not so straight-forward (see \cite[\S3.1.4]{hott-2013}). -There will be examples of sets later in this report. At this point it should be -noted that the term ``set'' is somewhat conflated; there is the notion of sets -from set-theory, in Agda types are denoted \texttt{Set}. I will use it -consistently to refer to a type $A$ as a set exactly if $\isSet\ A$ is a -proposition. +I will not give an example of a set at this point. It turns out that +proving e.g.\ $\isProp\ \bN$ directly is not so straightforward (see +\cite[\S3.1.4]{hott-2013}). Hedberg's theorem states that any type +with decidable equality is a set. There will be examples of sets later +in this report. At this point it should be noted that the term ``set'' +is somewhat conflated; there is the notion of sets from set-theory, in +Agda types are denoted \texttt{Set}. I will use it consistently to +refer to a type $A$ as a set exactly if $\isSet\ A$ is a proposition. As the reader may have guessed the next step in the hierarchy is the type: % @@ -239,34 +240,40 @@ exposition: Proposition: Homotopy levels are cumulative. That is, if $A \tp \MCU$ has homotopy level $n$ then so does it have $n + 1$. -Let $\left\Vert A \right\Vert = n$ denote that the level of $A$ is $n$. -Proposition: For any homotopic level $n$ this is a mere proposition. +For any level $n$ it is the case that to be of level $n$ is a mere proposition. % \section{A few lemmas} Rather than getting into the nitty-gritty details of Agda I venture to -take a more ``combinator-based'' approach. That is, I will use -theorems about paths already that have already been formalized. +take a more ``combinator-based'' approach. That is I will use +theorems about paths that have already been formalized. Specifically the results come from the Agda library \texttt{cubical} (\cite{cubical-demo}). I have used a handful of results from this -library as well as contributed a few lemmas myself.\footnote{The - module \texttt{Cat.Prelude} lists the upstream dependencies. As well - my contribution to \texttt{cubical} can be found in the git logs - which are available at - \hrefsymb{https://github.com/Saizan/cubical-demo}{\texttt{https://github.com/Saizan/cubical-demo}}.} +library as well as contributed a few lemmas myself% +\footnote{The module \texttt{Cat.Prelude} lists the upstream + dependencies. As well my contribution to \texttt{cubical} can be + found in the git logs which are available at + \hrefsymb{https://github.com/Saizan/cubical-demo}{\texttt{https://github.com/Saizan/cubical-demo}}. +}. -These theorems are all purely related to homotopy theory and cubical Agda and as -such not specific to the formalization of Category Theory. I will present a few -of these theorems here, as they will be used later in chapter -\ref{ch:implementation} throughout. +These theorems are all purely related to homotopy type theory and as +such not specific to the formalization of Category Theory. I will +present a few of these theorems here as they will be used throughout +chapter \ref{ch:implementation}. They should also give the reader some +intuition about the path type. \subsection{Path induction} \label{sec:pathJ} -The induction principle for paths intuitively gives us a way to reason about a -type family indexed by a path by only considering if said path is $\refl$ (the -\nomen{base case}{path induction}). For \emph{based path induction}, that equality is \emph{based} -at some element $a \tp A$. +The induction principle for paths intuitively gives us a way to reason +about a type family indexed by a path by only considering if said path +is $\refl$ (the \nomen{base case}{path induction}). For \emph{based + path induction}, that equality is \emph{based} at some element $a +\tp A$. -Let a type $A \tp \MCU$ and an element of the type $a \tp A$ be given. $a$ is said to be the base of the induction. Given a family of types: +\pagebreak[3] +\begin{samepage} +Let a type $A \tp \MCU$ and an element of the type $a \tp A$ be +given. $a$ is said to be the base of the induction.\linebreak[3] Given +a family of types: % $$ D \tp \prod_{b \tp A} \prod_{p \tp a ≡ b} \MCU @@ -283,7 +290,8 @@ We have the function: \begin{equation} \pathJ\ D\ d \tp \prod_{b \tp A} \prod_{p \tp a ≡ b} D\ b\ p \end{equation} -% +\end{samepage}% + A simple application of $\pathJ$ is for proving that $\var{sym}$ is an involution. Namely for any set $A \tp \MCU$, points $a, b \tp A$ and a path between them $p \tp a \equiv b$: @@ -293,8 +301,8 @@ between them $p \tp a \equiv b$: \var{sym}\ (\var{sym}\ p) ≡ p \end{equation} % -The proof will be by induction on $p$ and will be based at $a$. That is, $D$ -will be the family: +The proof will be by induction on $p$ and will be based at $a$. That +is $D$ will be the family: % \begin{align*} D & \tp \prod_{b' \tp A} \prod_{p \tp a ≡ b'} \MCU \\ @@ -319,7 +327,7 @@ definitionally. In summary \ref{eq:sym-invol} is inhabited by the term: % Another application of $\pathJ$ is for proving associativity of $\trans$. That is, given a type $A \tp \MCU$, elements of $A$, $a, b, c, d \tp A$ and paths -between them, $p \tp a \equiv b$, $q \tp b \equiv c$ and $r \tp c \equiv d$ we +between them $p \tp a \equiv b$, $q \tp b \equiv c$ and $r \tp c \equiv d$ we have the following: % \begin{equation} @@ -351,49 +359,52 @@ conclusion \ref{eq:cum-trans} is inhabited by the term: \pathJ\ T\ t\ d\ r \end{align*} % -We shall see another application on path induction in \ref{eq:pathJ-example}. +We shall see another application of path induction in \ref{eq:pathJ-example}. \subsection{Paths over propositions} \label{sec:lemPropF} -Another very useful combinator is $\lemPropF$: - -To `promote' this to a dependent path we can use another useful combinator; -$\lemPropF$. Given a type $A \tp \MCU$ and a type family on $A$; $P \tp A \to -\MCU$. Let $\var{propP} \tp \prod_{x \tp A} \isProp\ (P\ x)$ be the proof that -$P$ is a mere proposition for all elements of $A$. Furthermore say we have a -path between some two elements in $A$; $p \tp a_0 \equiv a_1$ then we can built -a heterogeneous path between any two elements of $p_0 \tp P\ a_0$ and $p_1 \tp -P\ a_1$: +Another very useful combinator is $\lemPropF$: Given a type $A \tp +\MCU$ and a type family on $A$; $D \tp A \to \MCU$. Let $\var{propD} +\tp \prod_{x \tp A} \isProp\ (D\ x)$ be the proof that $D$ is a mere +proposition for all elements of $A$. Furthermore say we have a path +between some two elements in $A$; $p \tp a_0 \equiv a_1$ then we can +built a heterogeneous path between any two elements of $d_0 \tp +D\ a_0$ and $d_1 \tp D\ a_1$. % $$ -\lemPropF\ \var{propP}\ p \tp \Path\ (\lambda\; i \mto P\ (p\ i))\ p_0\ p_1 +\lemPropF\ \var{propD}\ p \tp \Path\ (\lambda\; i \mto D\ (p\ i))\ d_0\ d_1 $$ % -This is quite a mouthful. So let me try to show how this is a very general and -useful result. +Note that $d_0$ and $d_1$, though points of the same family, have +different types. This is quite a mouthful. So let me try to show how +this is a very general and useful result. Often when proving equalities between elements of some dependent types -$\lemPropF$ can be used to boil this complexity down to showing that the -dependent parts of the type are mere propositions. For instance, saw we have a type: +$\lemPropF$ can be used to boil this complexity down to showing that +the dependent parts of the type are mere propositions. For instance +say we have a type: % $$ -T \defeq \sum_{a \tp A} P\ a +T \defeq \sum_{a \tp A} D\ a $$ % -For some proposition $P \tp A \to \MCU$. If we want to prove $t_0 \equiv t_1$ -for two elements $t_0, t_1 \tp T$ then this will be a pair of paths: +For some proposition $D \tp A \to \MCU$. That is we have $\var{propD} +\tp \prod_{a \tp A} \isProp\ (D\ a)$. If we want to prove $t_0 \equiv +t_1$ for two elements $t_0, t_1 \tp T$ then this will be a pair of +paths: % % \begin{align*} p \tp & \fst\ t_0 \equiv \fst\ t_1 \\ - & \Path\ (\lambda i \to P\ (p\ i))\ \snd\ t_0 \equiv \snd\ t_1 + & \Path\ (\lambda\; i \to D\ (p\ i))\ (\snd\ t_0)\ (\snd\ t_1) \end{align*} % -Here $\lemPropF$ directly allow us to prove the latter of these: +Here $\lemPropF$ directly allow us to prove the latter of these given +that we have already provided $p$. % $$ -\lemPropF\ \var{propP}\ p - \tp \Path\ (\lambda i \to P\ (p\ i))\ \snd\ t_0 \equiv \snd\ t_1 +\lemPropF\ \var{propD}\ p + \tp \Path\ (\lambda\; i \to D\ (p\ i))\ (\snd\ t_0)\ (\snd\ t_1) $$ % \subsection{Functions over propositions} @@ -407,9 +418,9 @@ $$ \subsection{Pairs over propositions} \label{sec:propSig} % -$\sum$-types preserve propositionality whenever its first component is a -proposition, and its second component is a proposition for all points of in the -left type. +$\sum$-types preserve propositionality whenever its first component is +a proposition, and its second component is a proposition for all +points of the left type. % $$ \mathit{propSig} \tp \isProp\ A \to \left(\prod_{a \tp A} \isProp\ (P\ a)\right) \to \isProp\ \left(\sum_{a \tp A} P\ a\right) diff --git a/doc/discussion.tex b/doc/discussion.tex index 3dc101a..56177ef 100644 --- a/doc/discussion.tex +++ b/doc/discussion.tex @@ -90,7 +90,7 @@ been put towards proving things that would not have been needed in classical Agda. The proofs that some given type is a proposition were provided as a strategy to simplify some otherwise very complicated proofs (e.g. \ref{eq:proof-prop-IsPreCategory} -and \label{eq:productPath}). Often these proofs would not be this +and \ref{eq:productPath}). Often these proofs would not be this complicated. If the J-rule holds definitionally the proof-assistant can help simplify these goals considerably. The lack of the J-rule has a significant impact on the complexity of these kinds of proofs. @@ -112,11 +112,6 @@ very simple example this is of course not a big problem, but there are examples in the source code where this gets more involved. \section{Future work} -\subsection{Agda \texttt{Prop}} -Jesper Cockx' work extending the universe-level-laws for Agda and the -\texttt{Prop}-type. -\TODO{Do I want to include this?} - \subsection{Compiling Cubical Agda} \label{sec:compiling-cubical-agda} Compilation of program written in Cubical Agda is currently not @@ -137,3 +132,9 @@ in the context of Category Theory. A fellow student here at Chalmers, Andreas Källberg, is currently working on proving the initiality conjecture\TODO{Citation}. He will be using this library to do so. + +\subsection{Proving laws of programs} +Another interesting thing would be to use the Kleisli formulation of +monads to prove properties of functional programs. The existence of +univalence will make it possible to re-use proofs stated in terms of +the monoidal formulation in this setting. diff --git a/doc/implementation.tex b/doc/implementation.tex index 69cba0c..ad2ed63 100644 --- a/doc/implementation.tex +++ b/doc/implementation.tex @@ -1,7 +1,7 @@ \chapter{Category Theory} \label{ch:implementation} -This implementaiton, including this report, is available as open -source software at: +The source code for this formalization, including this report, is +available as open source software at: % \begin{center} \gitlink @@ -17,7 +17,7 @@ link\footnote{% \begin{center} \doclink \end{center} -This implementation formalizes the following concepts: +The concepts formalized in this development are: % \begin{center} \begin{tabular}{ l l } @@ -41,6 +41,7 @@ Span category & \sourcelink{Cat.Categories.Span} \\ \end{tabular} \end{center} % +\begin{samepage} Furthermore the following items have been partly formalized: % \begin{center} @@ -54,70 +55,75 @@ Free category & \sourcelink{Cat.Categories.Free} \\ Monoids & \sourcelink{Cat.Category.Monoid} \\ \end{tabular} \end{center} +\end{samepage}% % As well as a range of various results about these. E.g.\ I have shown that the category of sets has products. In the following I aim to demonstrate some of the techniques employed in this formalization and in the interest of brevity I will not detail all the things I have -formalized. In stead, I have selected parts of this formalization that +formalized. In stead I have selected parts of this formalization that highlight some interesting proof techniques relevant to doing proofs in Cubical Agda. This chapter will focus on the definition of \emph{categories}, \emph{equivalences}, the \emph{opposite category}, the \emph{category of sets}, \emph{products}, the \emph{span category} and the two formulations of \emph{monads}. -One such technique that is pervasive to this formalization is the idea of -distinguishing types with more or less homotopical structure. To do this I have -followed the following design-principle: I have split concepts up into things -that represent ``data'' and ``laws'' about this data. The idea is that we can -provide a proof that the laws are mere propositions. As an example a category is -defined to have two members: `raw` which is a collection of the data and -`isCategory` which asserts some laws about that data. +One technique employed throughout this formalization is the idea of +distinguishing types with more or less homotopical structure. To do +this I have followed the following design-principle: I have split +concepts up into things that represent \emph{data} and \emph{laws} +about this data. The idea is that we can provide a proof that the laws +are mere propositions. As an example a category is defined to have two +members: $\var{raw}$ which is a collection of the data and +$\var{isCategory}$ which asserts some laws about that data. -This allows me to reason about things in a more ``standard mathematical way'', -where one can reason about two categories by simply focusing on the data. This -is achieved by creating a function embodying the ``equality principle'' for a -given type. +This allows me to reason about things in a more ``standard +mathematical way'', where one can reason about two categories by +simply focusing on the data. This is achieved by creating a function +embodying the equality principle for a given type. For the rest of this chapter I will present some of these results. For didactic reasons no source-code has been included in this chapter. To see the formal definitions the reader is referred to the -implementation which is linked in \S\ref{ch:implementation}. +implementation which is linked in the tables above. \section{Categories} \label{sec:categories} -The data for a category consist of a type for the sort of objects; a type for -the sort of arrows; an identity arrow and a composition operation for arrows. -Another record encapsulates some laws about this data: associativity of -composition, identity law for the identity morphism. These are standard -constituents of a category and can be found in typical mathematical expositions -on the topic. We, however, impose one further requirement on what it means to be -a category, namely that the type of arrows form a set. +The data for a category consist of a type for the sort of objects; a +type for the sort of arrows; an identity arrow and a composition +operation for arrows. Another record encapsulates some laws about +this data: associativity of composition, identity law for the identity +morphism. These are standard constituents of a category and can be +found in typical mathematical expositions on the topic. We shall +impose one further requirement on what it means to be a category, +namely that the type of arrows form a set. -Such categories are called \nomen{1-categories}{1-category}. It is possible to relax -this requirement. This would lead to the notion of higher categories (\cite[p. - 307]{hott-2013}). For the purpose of this project, however, this report will -restrict itself to 1-categories\index{1-category}. Generalizing this work to -higher categories would be a very natural possible extension of this work. +Such categories are called \nomen{1-categories}{1-category}. It is +possible to relax this requirement. This would lead to the notion of +higher categories (\cite[p. 307]{hott-2013}). For the purpose of this +thesis however, this report will restrict itself to +1-categories\index{1-category}. Generalizing this work to higher +categories would be a very natural extension of this work. Raw categories satisfying all of the above requirements are called a -\nomenindex{pre categories}. As a further requirement to be a proper category we +\nomenindex{pre-categories}. As a further requirement to be a proper category we require it to be univalent. Before we can define this, I must introduce two more definitions: If we let $p$ be a witness to the identity law, which formally is: % \begin{equation} \label{eq:identity} \var{IsIdentity} \defeq - \prod_{A\ B \tp \Object} \prod_{f \tp \Arrow\ A\ B} + \prod_{A, B \tp \Object} \prod_{f \tp \Arrow\ A\ B} \left(\id \lll f \equiv f\right) \x \left(f \lll \id \equiv f\right) \end{equation} % -Then we can construct the identity isomorphism $\idIso \tp \identity, -\identity, p \tp A \approxeq A$ for any object $A$. Here $\approxeq$ denotes -isomorphism on objects (whereas $\cong$ denotes isomorphism of types). This will -be elaborated further on in sections \S\ref{sec:equiv} and -\S\ref{sec:univalence}. Moreover, due to substitution for paths we can construct -an isomorphism from \emph{any} path: +Then we can construct the identity isomorphism $\idIso \tp (\identity, +\identity, p) \tp A \approxeq A$ for any object $A$. Here $\approxeq$ +denotes isomorphism on objects (whereas $\cong$ denotes isomorphism on +types). This will be elaborated further on in sections +\S\ref{sec:equiv} and \S\ref{sec:univalence}. Moreover due to +substitution for paths we can construct an isomorphism from \emph{any} +path: % \begin{equation} \idToIso \tp A ≡ B → A ≊ B @@ -140,12 +146,13 @@ Note that \ref{eq:cat-univ} is \emph{not} the same as: (A \equiv B) \simeq (A \approxeq B) \end{equation} % -However the two are logically equivalent: One can construct the latter from the -former simply by ``forgetting'' that $\idToIso$ plays the role of the -equivalence. The other direction is more involved and will be discussed in -section \S\ref{sec:univalence}. +However the two are logically equivalent: One can construct the latter +from the former simply by ``forgetting'' that $\idToIso$ plays the +role of the equivalence. The other direction is more involved and will +be discussed in section \S\ref{sec:univalence}. -In summary, the definition of a category is the following collection of data: +In summary the definition of a category is the following collection of +data: % \begin{align} \Object & \tp \Type \\ @@ -180,19 +187,20 @@ composition (left-to-right, diagrammatic order) is denoted $\rrr$. The objects ($A$, $B$ and $C$) and arrow ($f$, $g$, $h$) are implicitly universally quantified. -With all this in place it is now possible to prove that all the laws are indeed -mere propositions. Most of the proofs simply use the fact that the type of -arrows are sets. This is because most of the laws are a collection of equations -between arrows in the category. And since such a proof does not have any content -exactly because the type of arrows form a set, two witnesses must be the same. -All the proofs are really quite mechanical. Lets have a look at one of them. -Proving that \ref{eq:identity} is a mere proposition: +With all this in place it is now possible to prove that all the laws +are indeed mere propositions. Most of the proofs simply use the fact +that the type of arrows are sets. This is because most of the laws are +a collection of equations between arrows in the category. And since +such a proof does not have any content exactly because the type of +arrows form a set, two witnesses must be the same. All the proofs are +really quite mechanical. Let us have a look at one of them: Proving +that \ref{eq:identity} is a mere proposition: % \begin{equation} \isProp\ \var{IsIdentity} \end{equation} % -There are multiple ways to prove this. Perhaps one of the more intuitive proofs +There are multiple ways to do this. Perhaps one of the more intuitive proofs is by way of the `combinators' $\propPi$ and $\propSig$ presented in sections \S\ref{sec:propPi} and \S\ref{sec:propSig}: % @@ -202,25 +210,26 @@ is by way of the `combinators' $\propPi$ and $\propSig$ presented in sections \propSig & \tp \isProp\ A \to \left(\prod_{a \tp A} \isProp\ (P\ a)\right) \to \isProp\ \left(\sum_{a \tp A} P\ a\right) \end{align*} % -So the proof goes like this: We `eliminate' the 3 function abstractions by -applying $\propPi$ three times. So our proof obligation becomes: +The proof goes like this: We `eliminate' the 3 function abstractions +by applying $\propPi$ three times. So our proof obligation becomes: % $$ \isProp\ \left( \left( \id \comp f \equiv f \right) \x \left( f \comp \id \equiv f \right) \right) $$ % Then we eliminate the (non-dependent) sigma-type by applying $\propSig$ giving -us the two obligations: $\isProp\ (\id \comp f \equiv f)$ and $\isProp\ (f \comp +us the two obligations $\isProp\ (\id \comp f \equiv f)$ and $\isProp\ (f \comp \id \equiv f)$ which follows from the type of arrows being a set. -This example illustrates nicely how we can use these combinators to reason about -`canonical' types like $\sum$ and $\prod$. Similar combinators can be defined at -the other homotopic levels. These combinators are however not applicable in -situations where we want to reason about other types - e.g.\ types we have -defined ourselves. For instance, after we have proven that all the projections -of pre categories are propositions, then we would like to bundle this up to show -that the type of pre categories is also a proposition. Formally: +This example illustrates nicely how we can use these combinators to +reason about `canonical' types like $\sum$ and $\prod$. Similar +combinators can be defined at the other homotopic levels. These +combinators are however not applicable in situations where we want to +reason about other types e.g.\ types we have defined ourselves. For +instance, after we have proven that all the projections of +pre-categories are propositions, we would like to bundle this up to +show that the type of pre-categories is also a proposition. Formally: % \begin{equation} \label{eq:propIsPreCategory} @@ -235,19 +244,20 @@ Where The definition of $\IsPreCategory$ is the triple: \var{arrowsAreSets} & \tp \var{ArrowsAreSets} \end{align*} % -Each corresponding to the first three laws for categories. Note that since -$\IsPreCategory$ is not formulated with a chain of sigma-types we wont have any -combinators available to help us here. In stead the paths must be used directly. +Each corresponding to the first three laws for categories. Note that +since $\IsPreCategory$ is not formulated with a chain of sigma-types +we will not have any combinators available to help us here. In stead +the path type must be used directly. -\ref{eq:propIsPreCategory} is judgmentally the same as: +The type \ref{eq:propIsPreCategory} is judgmentally the same as: % $$ -\prod_{a\ b \tp \IsPreCategory} a \equiv b +\prod_{a, b \tp \IsPreCategory} a \equiv b $$ % -So to prove the proposition let $a\ b \tp \IsPreCategory$ be given. To +So to prove the proposition let $a, b \tp \IsPreCategory$ be given. To prove the equality $a \equiv b$ is to give a continuous path from the -index-type into the path-space. I.e.\ a function $I \to +index-type into the path-space. I.e.\ a function $\I \to \IsPreCategory$. This path must satisfy being being judgmentally the same as $a$ at the left endpoint and $b$ at the right endpoint. We know we can form a continuous path between all projections of $a$ and @@ -261,8 +271,8 @@ $$ a.\isIdentity \equiv b.\isIdentity $$ % -So to give the continuous function $I \to \IsPreCategory$, which is our goal, we -introduce $i \tp I$ and proceed by constructing an element of $\IsPreCategory$ +So to give the continuous function $\I \to \IsPreCategory$, which is our goal, we +introduce $i \tp \I$ and proceed by constructing an element of $\IsPreCategory$ by using the fact that all the projections are propositions to generate paths between all projections. Once we have such a path e.g.\ $p \tp a.\isIdentity \equiv b.\isIdentity$ we can eliminate it with $i$ and thus obtain $p\ i \tp @@ -299,9 +309,9 @@ unique. The situation is a bit more complicated when we have a dependent type. For instance, when we want to show that $\IsCategory$ is a mere proposition. The type $\IsCategory$ is a record with two fields, a -witness to being a pre category and the univalence condition. Recall +witness to being a pre-category and the univalence condition. Recall that the univalence condition is indexed by the identity-proof. So to -follow the same recipe as above, let $a\ b \tp \IsCategory$ be given, +follow the same recipe as above, let $a, b \tp \IsCategory$ be given, to show them equal, we now need to give two paths. One homogeneous: % $$ @@ -463,7 +473,7 @@ equalities and isomorphisms (on arrows). It is worthwhile to dwell on this for a few seconds. This type looks very similar to univalence for types and is therefore perhaps a bit more intuitive to grasp the implications of. Of course univalence for types (which is a proposition -- i.e.\ provable) does not imply -univalence of all pre category since morphisms in a category are not regular +univalence of all pre-category since morphisms in a category are not regular functions -- in stead they can be thought of as a generalization hereof. The univalence criterion therefore is simply a way of restricting arrows to behave similarly to maps. @@ -581,7 +591,7 @@ over-bar. So e.g.\ $\idToIso$ is a function in the underlying category and the corresponding thing is denoted $\wideoverbar{\idToIso}$ in the opposite category. -Showing that this forms a pre category is rather straightforward. +Showing that this forms a pre-category is rather straightforward. % $$ h \rrr (g \rrr f) \equiv h \rrr g \rrr f @@ -600,7 +610,7 @@ Finally, that the arrows form sets just follows by flipping the order of the arguments. Or in other words; since $\Arrow\ A\ B$ is a set for all $A\;B \tp \Object$ then so is $Arrow\ B\ A$. -Now, to show that this category is univalent is not as straight-forward. Luckily +Now, to show that this category is univalent is not as straightforward. Luckily section \S\ref{sec:equiv} gave us some tools to work with equivalences. We saw that we can prove this category univalent by giving an inverse to $\wideoverbar{\idToIso} \tp (A \equiv B) \to (A \wideoverbar{\approxeq} B)$. @@ -624,7 +634,7 @@ follows: \wideoverbar{\isoToId} \comp \wideoverbar{\idToIso} & = \isoToId \comp \shufflef \comp \wideoverbar{\idToIso} \\ -%% ≡⟨ cong (λ φ → φ x) (cong (λ φ → η ⊙ shuffle ⊙ φ) (funExt lem)) ⟩ \\ +%% ≡⟨ cong (λ \; φ → φ x) (cong (λ \; φ → η ⊙ shuffle ⊙ φ) (funExt lem)) ⟩ \\ % & \equiv \isoToId \comp \shufflef \comp \inv{\shufflef} \comp \idToIso @@ -641,7 +651,7 @@ follows: The other direction is analogous. The lemma used in step 2 of this proof states that $\wideoverbar{idToIso} \equiv -\inv{\shufflef} \comp \idToIso$. This is a rather straight-forward proof +\inv{\shufflef} \comp \idToIso$. This is a rather straightforward proof since being-an-inverse-of is a proposition, so it suffices to show that their first components are equal, but this holds judgmentally. @@ -673,7 +683,7 @@ homotopic sets. This is encapsulated in Agda with the following type: % $$\Set \defeq \sum_{A \tp \MCU} \isSet\ A$$ % -The more straight-forward notion of a category where the objects are types is +The more straightforward notion of a category where the objects are types is not a valid \mbox{(1-)category}. This stems from the fact that types in cubical Agda types can have higher homotopic structure. @@ -681,7 +691,7 @@ Univalence does not follow immediately from univalence for types: % $$(A \equiv B) \simeq (A \simeq B)$$ % -Because here $A\ B \tp \Type$ whereas the objects in this category have the type +Because here $A, B \tp \Type$ whereas the objects in this category have the type $\Set$ so we cannot form the type $\var{hA} \simeq \var{hB}$ for objects $\var{hA}\;\var{hB} \tp \Set$. In stead I show that this category satisfies: @@ -956,7 +966,7 @@ underlying category. Given that $p$ is the chosen proof of % \begin{align} \label{eq:productPath} -λ\ i → d_{\pairA} \lll p\ i ≡ 2 a_{\pairA} × d_{\pairB} \lll p\ i ≡ a_{\pairB} +λ \; i → d_{\pairA} \lll p\ i ≡ 2 a_{\pairA} × d_{\pairB} \lll p\ i ≡ a_{\pairB} \end{align} % And these paths are in the type of the hom-set of the underlying category, so @@ -1006,7 +1016,7 @@ $$ This we get from \ref{eq:productEqPrinc} and the fact that homotopical structure is cumulative. -This finishes the proof that this is a valid pre category. +This finishes the proof that this is a valid pre-category. \subsubsection{Univalence} To prove that this is a proper category it must be shown that it is univalent. @@ -1032,8 +1042,8 @@ The next types will be the triple: \label{eq:univ-1} \begin{split} p \tp & X \equiv Y \\ -& \Path\ (λ i → \Arrow\ (p\ i)\ \mathcal{A})\ x_{\mathcal{A}}\ y_{\mathcal{A}} \\ -& \Path\ (λ i → \Arrow\ (p\ i)\ \mathcal{B})\ x_{\mathcal{B}}\ y_{\mathcal{B}} +& \Path\ (λ \; i → \Arrow\ (p\ i)\ \mathcal{A})\ x_{\mathcal{A}}\ y_{\mathcal{A}} \\ +& \Path\ (λ \; i → \Arrow\ (p\ i)\ \mathcal{B})\ x_{\mathcal{B}}\ y_{\mathcal{B}} \end{split} %% \end{split} \end{align} @@ -1045,8 +1055,8 @@ isomorphism, and create a path from this: \label{eq:univ-2} \begin{split} \var{iso} \tp & X \approxeq Y \\ -& \Path\ (λ i → \Arrow\ (\widetilde{p}\ i)\ \mathcal{A})\ x_{\mathcal{A}}\ y_{\mathcal{A}} \\ -& \Path\ (λ i → \Arrow\ (\widetilde{p}\ i)\ \mathcal{B})\ x_{\mathcal{B}}\ y_{\mathcal{B}} +& \Path\ (λ \; i → \Arrow\ (\widetilde{p}\ i)\ \mathcal{A})\ x_{\mathcal{A}}\ y_{\mathcal{A}} \\ +& \Path\ (λ \; i → \Arrow\ (\widetilde{p}\ i)\ \mathcal{B})\ x_{\mathcal{B}}\ y_{\mathcal{B}} \end{split} \end{align} % @@ -1074,7 +1084,7 @@ This proof of this has been omitted but can be found in the module: \emph{Proposition} \ref{eq:univ-2} is isomorphic to \ref{eq:univ-3}: For this I will show two corollaries of \ref{eq:coeCod}: For an isomorphism $(\iota, \inv{\iota}, \var{inv}) \tp A \cong B$, arrows $f \tp \Arrow\ A\ X$, $g \tp -\Arrow\ B\ X$ and a heterogeneous path between them, $q \tp \Path\ (\lambda i +\Arrow\ B\ X$ and a heterogeneous path between them, $q \tp \Path\ (\lambda\; i \to p_{\var{dom}}\ i)\ f\ g$, where $p_{\var{dom}} \tp \Arrow\ A\ X \equiv \Arrow\ B\ X$ is a path induced by $\var{iso}$, we have the following two results @@ -1095,9 +1105,9 @@ Now we can prove the equivalence in the following way: Given $(f, \inv{f}, \var{inv}_f) \tp X \cong Y$ and two heterogeneous paths % \begin{align*} -p_{\mathcal{A}} & \tp \Path\ (\lambda i \to p_{\var{dom}}\ i)\ x_{\mathcal{A}}\ y_{\mathcal{A}}\\ +p_{\mathcal{A}} & \tp \Path\ (\lambda\; i \to p_{\var{dom}}\ i)\ x_{\mathcal{A}}\ y_{\mathcal{A}}\\ % -q_{\mathcal{B}} & \tp \Path\ (\lambda i \to p_{\var{dom}}\ i)\ x_{\mathcal{B}}\ y_{\mathcal{B}} +q_{\mathcal{B}} & \tp \Path\ (\lambda\; i \to p_{\var{dom}}\ i)\ x_{\mathcal{B}}\ y_{\mathcal{B}} \end{align*} % all as in \ref{eq:univ-2}. I use $p_{\var{dom}}$ here again to mean the path @@ -1163,8 +1173,8 @@ It then remains to construct the two paths: \begin{align} \begin{split} \label{eq:product-paths} -& \Path\ (λ i → \widetilde{p}_{\mathcal{A}}\ i)\ x_{\mathcal{A}}\ y_{\mathcal{A}}\\ -& \Path\ (λ i → \widetilde{p}_{\mathcal{B}}\ i)\ x_{\mathcal{B}}\ y_{\mathcal{B}} +& \Path\ (λ \; i → \widetilde{p}_{\mathcal{A}}\ i)\ x_{\mathcal{A}}\ y_{\mathcal{A}}\\ +& \Path\ (λ \; i → \widetilde{p}_{\mathcal{B}}\ i)\ x_{\mathcal{B}}\ y_{\mathcal{B}} \end{split} \end{align} % @@ -1172,7 +1182,7 @@ This is achieved with the following lemma: % \begin{align} \prod_{a \tp A} \prod_{b \tp B} \prod_{q \tp A \equiv B} \var{coe}\ q\ a ≡ b → -\Path\ (λ i → q\ i)\ a\ b +\Path\ (λ \; i → q\ i)\ a\ b \end{align} % Which is used without proof. See the implementation for the details. @@ -1201,12 +1211,17 @@ the proof uses the fact that isomorphism-of is propositional and that arrows (in both categories) are sets. The reader is referred to the implementation for the gory details. % -\subsection{Propositionality of products} +\subsection{Products are propositions} % Now that we have constructed the span category\index{span category} I will demonstrate how to use this to prove that products are -propositional. I will do this by showing that terminal objects in this -category are equivalent to products: +propositions. On the face of it this may seem surprising. Products +look like they are a structure on categories. After all it consist of +a select element and two arrows given some two objects. If formulated +in set theory this would be the case but in the present setting +univalence of categories give us that products are properties. I will +show this by showing that terminal objects in the span category are +equivalent to products: % \begin{align} \var{Terminal} ≃ \var{Product}\ ℂ\ \mathcal{A}\ \mathcal{B} @@ -1248,9 +1263,9 @@ is the proof that $f$ satisfies \ref{eq:pairCondRev}). The proof will be a pair of proofs: % \begin{alignat}{3} - p \tp & \Path\ (\lambda i \to \Arrow\ X\ Y)\quad + p \tp & \Path\ (\lambda\; i \to \Arrow\ X\ Y)\quad && f\quad && y_𝒜 \x y_ℬ \\ - & \Path\ (\lambda i \to \Phi\ (p\ i))\quad + & \Path\ (\lambda\; i \to \Phi\ (p\ i))\quad && \phi_f\quad && \phi_{y_𝒜 \x y_ℬ} \end{alignat} % @@ -1283,7 +1298,7 @@ preserve homotopic levels along with \ref{eq:termProp} we get our final result. That in any category: % \begin{align} -\prod_{A\ B \tp \Object} \isProp\ (\var{Product}\ \bC\ A\ B) +\prod_{A, B \tp \Object} \isProp\ (\var{Product}\ \bC\ A\ B) \end{align} % \section{Functors and natural transformations} diff --git a/doc/introduction.tex b/doc/introduction.tex index 59c1037..d4effb8 100644 --- a/doc/introduction.tex +++ b/doc/introduction.tex @@ -6,22 +6,27 @@ of equality: \nomenindex{judgmental equality} and \nomenindex{propositional equality}. Judgmental equality is a property of the type system. Judgmental equality on the other hand is usually defined \emph{within} the system. When introducing definitions this -report will use the notation $\defeq$. Judgmental equalities written -$=$. For propositional equalities the notation $\equiv$ is used. +report will use the symbol $\defeq$. Judgmental equalities will be +denoted with $=$ and for propositional equalities the notation +$\equiv$ is used. -For judgmental equality there are some properties that it must -satisfy. \nomenindex{sound}, enjoy \nomenindex{canonicity} and be a -\nomen{congruence relation}. Soundness means that things judged to be -equal are equal with respects to the model of the theory (the meta -theory). It must be a congruence relation because otherwise the -relation certainly does not adhere to our notion of equality. One -would be able to conclude things like: $x \equiv y \rightarrow f\ x -\nequiv f\ y$. Canonicity means that any well typed term evaluates to -a \emph{canonical} form. For example for a closed term $e \tp \bN$ it -will be the case that $e$ reduces to $n$ applications of -$\mathit{suc}$ to $0$ for some $n$; $e = \mathit{suc}^n\ 0$. Without -canonicity terms in the language can get ``stuck'' -- meaning that -they do not reduce to a canonical form. +The rules of judgmental equality are related with $β$- and +$η$-reduction which gives a notion of computation in a given type +theory. +% +There are some properties that one usually want judgmental equality to +satisfy. It must be \nomenindex{sound}, enjoy \nomenindex{canonicity} +and be a \nomenindex{congruence relation}. Soundness means that things +judged to be equal are equal with respects to the \nomenindex{model} +of the theory or the \emph{meta theory}. It must be a congruence +relation because otherwise the relation certainly does not adhere to +our notion of equality. One would be able to conclude things like: $x +\equiv y \rightarrow f\ x \nequiv f\ y$. Canonicity means that any +well typed term evaluates to a \emph{canonical} form. For example for +a closed term $e \tp \bN$ it will be the case that $e$ reduces to $n$ +applications of $\mathit{suc}$ to $0$ for some $n$; $e = +\mathit{suc}^n\ 0$. Without canonicity terms in the language can get +``stuck'' meaning that they do not reduce to a canonical form. To work as a programming languages it is necessary for judgmental equality to be \nomenindex{decidable}. Being decidable simply means @@ -34,27 +39,27 @@ is not in general possible to decide the correctness of logical propositions (cf.\ Hilbert's \emph{entscheidigungsproblem}). There are two flavors of type-theory. \emph{Intensional-} and -\emph{extensional-} type theory. Identity types in extensional type -theory are required to be \nomen{propositions}{proposition}. That is, -a type with at most one inhabitant. In extensional type thoery the -principle of reflection +\emph{extensional-} type theory (ITT and ETT respectively). Identity +types in extensional type theory are required to be +\nomen{propositions}{proposition}. That is, a type with at most one +inhabitant. In extensional type theory the principle of reflection % $$a ≡ b → a = b$$ % is enough to make type checking undecidable. This report focuses on -Agda which at a glance can be thought of a version of intensional type -theory. Pattern-matching in regular Agda let's one prove -\nomenindex{axiom K}. Axiom K states that any two identity proofs are -propositionally identical. +Agda which at a glance can be thought of as a version of intensional +type theory. Pattern-matching in regular Agda lets one prove +\nomenindex{Uniqueness of Identity Proofs} (UIP). UIP states that any +two identity proofs are propositionally identical. -The usual notion of propositional equality in \nomenindex{Intensional - Type Theory} (ITT) is quite restrictive. In the next section a few -motivating examples will highlight this. There exist techniques to -circumvent these problems, as we shall see. This thesis will explore -an extension to Agda that redefines the notion of propositional -equality and as such is an alternative to these other techniques. The -extension is called cubical Agda. Cubical Agda drops Axiom K as this -does not permit \nomenindex{functional extensionality} and +The usual notion of propositional equality in ITT is quite +restrictive. In the next section a few motivating examples will +highlight this. There exist techniques to circumvent these problems, +as we shall see. This thesis will explore an extension to Agda that +redefines the notion of propositional equality and as such is an +alternative to these other techniques. The extension is called cubical +Agda. Cubical Agda drops UIP as this does not permit +\nomenindex{functional extensionality} and \nomenindex{univalence}. What makes this extension particularly interesting is that it gives a \emph{constructive} interpretation of univalence. What all this means will be elaborated in the following @@ -69,74 +74,53 @@ some limitations inherent in ITT and -- by extension -- Agda. \label{sec:functional-extensionality}% Consider the functions: % -\begin{multicols}{2} - \noindent% - \begin{equation*}% - f \defeq \lambda\ (n \tp \bN) \to (0 + n \tp \bN) - \end{equation*}% - \begin{equation*}% - g \defeq \lambda\ (n \tp \bN) \to (n + 0 \tp \bN) - \end{equation*}% -\end{multicols}% +\begin{align*}% +\var{zeroLeft} & \defeq \lambda\; (n \tp \bN) \to (0 + n \tp \bN) \\ +\var{zeroRight} & \defeq \lambda\; (n \tp \bN) \to (n + 0 \tp \bN) +\end{align*}% % -The term $n + 0$ is -\nomenindex{definitionally} equal to $n$, which we -write as $n + 0 = n$. This is also called -\nomenindex{judgmental equality}. -We call it definitional equality because the \emph{equality} arises -from the \emph{definition} of $+$ which is: +The term $n + 0$ is \nomenindex{definitionally} equal to $n$, which we +write as $n + 0 = n$. This is also called \nomenindex{judgmental + equality}. We call it definitional equality because the +\emph{equality} arises from the \emph{definition} of $+$ which is: % \begin{align*} - + & \tp \bN \to \bN \to \bN \\ - n + 0 & \defeq n \\ + + & \tp \bN \to \bN \to \bN \\ + n + 0 & \defeq n \\ n + (\suc{m}) & \defeq \suc{(n + m)} \end{align*} % -Note that $0 + n$ is \emph{not} definitionally equal to $n$. $0 + n$ -is in normal form. I.e.; there is no rule for $+$ whose left hand side -matches this expression. We \emph{do}, however, have that they are -\nomen{propositionally}{propositional equality} equal, which we write -as $n + 0 \equiv n$. Propositional equality means that there is a -proof that exhibits this relation. Since equality is a transitive -relation we have that $n + 0 \equiv 0 + n$. - -Unfortunately we don't have $f \equiv g$. There is no way to construct -a proof asserting the obvious equivalence of $f$ and $g$. Actually -showing this is outside the scope of this text. Essentially it would -involve giving a model for our type theory that validates all our -axioms but where $f \equiv g$ is not true. We cannot show that they -are equal, even though we can prove them equal for all points. For -functions this is exactly the notion of equality that we are -interested in: Functions are considered equal when they are equal for -all inputs. This is called \nomenindex{point wise equality}, where the -\emph{points} of a function refer to its arguments. - -%% In the context of category theory functional extensionality is e.g. -%% needed to show that representable functors are indeed functors. The -%% representable functor is defined for a fixed category $\bC$ and an -%% object $X \in \bC$. It's map on objects is defined thus: -%% % -%% \begin{align*} -%% \lambda\ A \to \Arrow\ X\ A -%% \end{align*} -%% % -%% That is, it maps objects to arrows. So, it's map on arrows must map an arrow $\Arrow\ A\ B$ to an -%% The map on objects is defined thus: -%% % -%% \begin{align*} -%% \lambda f \to -%% \end{align*} -%% % -%% The proof obligation that this satisfies the identity law of functors -%% ($\fmap\ \idFun \equiv \idFun$) thus becomes: -%% % -%% \begin{align*} -%% \Hom(A, \idFun_{\bX}) = (\lambda\ g \to \idFun \comp g) \equiv \idFun_{\Sets} -%% \end{align*} -%% % -%% One needs functional extensionality to ``go under'' the function arrow and apply -%% the (left) identity law of the underlying category to prove $\idFun \comp g -%% \equiv g$ and thus close the goal. +Note that $0 + n$ is \emph{not} definitionally equal to $n$. This is +because $0 + n$ is in normal form. I.e.\ there is no rule for $+$ +whose left hand side matches this expression. We do however have that +they are \nomen{propositionally}{propositional equality} equal, which +we write as $n \equiv n + 0$. Propositional equality means that there +is a proof that exhibits this relation. We can do induction over $n$ +to prove this: +% +\begin{align} +\label{eq:zrn} +\begin{split} +\var{zrn}\ & \tp ∀ n → n ≡ \var{zeroRight}\ n \\ +\var{zrn}\ \var{zero} & \defeq \var{refl} \\ +\var{zrn}\ (\var{suc}\ n) & \defeq \var{cong}\ \var{suc}\ (\var{zrn}\ n) +\end{split} +\end{align} +% +This show that zero is a right neutral element hence the name $\var{zrn}$. +Since equality is a transitive relation we have that $\forall n \to +\var{zeroLeft}\ n \equiv \var{zeroRight}\ n$. Unfortunately we don't +have $\var{zeroLeft} \equiv \var{zeroRight}$. There is no way to +construct a proof asserting the obvious equivalence of +$\var{zeroLeft}$ and $\var{zeroRight}$. Actually showing this is +outside the scope of this text. Essentially it would involve giving a +model for our type theory that validates all our axioms but where +$\var{zeroLeft} \equiv \var{zeroRight}$ is not true. We cannot show +that they are equal even though we can prove them equal for all +points. For functions this is exactly the notion of equality that we +are interested in: Functions are considered equal when they are equal +for all inputs. This is called \nomenindex{pointwise equality}, where +the \emph{points} of a function refer to its arguments. % \subsection{Equality of isomorphic types} % @@ -155,7 +139,6 @@ without thinking twice. Unfortunately such an identification can not be performed in ITT. More specifically what we are interested in is a way of identifying - \nomenindex{equivalent} types. I will return to the definition of equivalence later in section \S\ref{sec:equiv}, but for now it is sufficient to think of an equivalence as a one-to-one correspondence. @@ -165,27 +148,30 @@ The principle of univalence says that: $$\mathit{univalence} \tp (A \simeq B) \simeq (A \equiv B)$$ % In particular this allows us to construct an equality from an equivalence -($\mathit{ua} \tp (A \simeq B) \to (A \equiv B)$) and vice versa. +% +$$\mathit{ua} \tp (A \simeq B) \to (A \equiv B)$$ +% +and vice versa. \section{Formalizing Category Theory} % -The above examples serve to illustrate a limitation of ITT. One case where these -limitations are particularly prohibitive is in the study of Category Theory. At -a glance category theory can be described as ``the mathematical study of -(abstract) algebras of functions'' (\cite{awodey-2006}). By that token -functional extensionality is particularly useful for formulating Category -Theory. In Category theory it is also common to identify isomorphic structures -and univalence gives us a way to make this notion precise. In fact we can -formulate this requirement within our formulation of categories by requiring the -\emph{categories} themselves to be univalent as we shall see. +The above examples serve to illustrate a limitation of ITT. One case +where these limitations are particularly prohibitive is in the study +of Category Theory. At a glance category theory can be described as +``the mathematical study of (abstract) algebras of functions'' +(\cite{awodey-2006}). By that token functional extensionality is +particularly useful for formulating Category Theory. In Category +theory it is also commonplace to identify isomorphic structures and +univalence gives us a way to make this notion precise. In fact we can +formulate this requirement within our formulation of categories by +requiring the \emph{categories} themselves to be univalent as we shall +see in \S\ref{sec:univalence}. \section{Context} \label{sec:context} % The idea of formalizing Category Theory in proof assistants is not new. There -are a multitude of these available online. Just as a first reference see this -question on Math Overflow: \cite{mo-formalizations}. Notably these -implementations of category theory in Agda: +are a multitude of these available online. Notably: % \begin{itemize} \item @@ -217,12 +203,12 @@ other shortcomings, e.g. you lose \nomenindex{canonicity} Another approach is to use the \emph{setoid interpretation} of type theory (\cite{hofmann-1995,huber-2016}). With this approach one works -with \nomenindex{extensional sets} $(X, \sim)$, that is a type $X \tp +with \nomenindex{extensional sets} $(X, \sim)$. That is a type $X \tp \MCU$ and an equivalence relation $\sim\ \tp X \to X \to \MCU$ on that type. Under the setoid interpretation the equivalence relation serve as a sort of ``local'' propositional equality. Since the developer -gets to pick this relation it is not guaranteed to be a congruence -relation a priori. So this must be verified manually by the developer. +gets to pick this relation it is not a\~priori a congruence +relation. So this must be verified manually by the developer. Furthermore, functions between different setoids must be shown to be setoid homomorphism, that is; they preserve the relation. @@ -237,12 +223,14 @@ makes it very cumbersome to work with in practice (\cite[p. 4]{huber-2016}). \section{Conventions} -In the remainder of this paper I will use the term -\nomenindex{Type} to describe -- -well, types. Thereby diverging from the notation in Agda where the keyword -\texttt{Set} refers to types. -\nomenindex{Set} on the other hand shall refer to the -homotopical notion of a set. I will also leave all universe levels implicit. +In the remainder of this paper I will use the term \nomenindex{Type} +to describe -- well -- types. Thereby departing from the notation in +Agda where the keyword \texttt{Set} refers to types. \nomenindex{Set} +on the other hand shall refer to the homotopical notion of a set. I +will also leave all universe levels implicit. This of course does not +mean that a statement such as $\MCU \tp \MCU$ means that we have +type-in-type but rather that the arguments to the universes are +implicit. And I use the term \nomenindex{arrow} to refer to morphisms in a category, @@ -253,11 +241,13 @@ whereas the terms shall be reserved for talking about type theoretic functions; i.e. functions in Agda. -$\defeq$ will be used for introducing definitions. $=$ will be used to for -judgmental equality and $\equiv$ will be used for propositional equality. +As already noted $\defeq$ will be used for introducing definitions $=$ +will be used to for judgmental equality and $\equiv$ will be used for +propositional equality. All this is summarized in the following table: - +% +\begin{samepage} \begin{center} \begin{tabular}{ c c c } Name & Agda & Notation \\ @@ -277,3 +267,4 @@ Judgmental equality & \null & $̱=$ \\ Propositional equality & \null & $̱\equiv$ \end{tabular} \end{center} +\end{samepage} diff --git a/doc/macros.tex b/doc/macros.tex index 4d872b0..da71215 100644 --- a/doc/macros.tex +++ b/doc/macros.tex @@ -127,3 +127,4 @@ \newcommand\coe{\varindex{coe}} \newcommand\Monoidal{\varindex{Monoidal}} \newcommand\Kleisli{\varindex{Kleisli}} +\newcommand\I{\mathds{I}} diff --git a/doc/main.tex b/doc/main.tex index 2d5ad96..74d37b7 100644 --- a/doc/main.tex +++ b/doc/main.tex @@ -1,4 +1,5 @@ \documentclass[a4paper]{report} +%% \documentclass[tightpage]{preview} %% \documentclass[compact,a4paper]{article} \input{packages.tex} @@ -49,6 +50,7 @@ \myfrontmatter \maketitle \input{abstract.tex} +\input{acknowledgements.tex} \tableofcontents \mainmatter % diff --git a/doc/packages.tex b/doc/packages.tex index ba2ccba..738bf95 100644 --- a/doc/packages.tex +++ b/doc/packages.tex @@ -16,13 +16,14 @@ %% \hypersetup{allbordercolors={darkorange}} \hypersetup{hidelinks} \usepackage{graphicx} +%% \usepackage[active,tightpage]{preview} \usepackage{parskip} \usepackage{multicol} \usepackage{amssymb,amsmath,amsthm,stmaryrd,mathrsfs,wasysym} \usepackage[toc,page]{appendix} \usepackage{xspace} -\usepackage[a4paper,top=3cm,bottom=3cm]{geometry} +\usepackage[paper=a4paper,top=3cm,bottom=3cm]{geometry} \usepackage{makeidx} \makeindex % \setlength{\parskip}{10pt} @@ -83,7 +84,7 @@ \newunicodechar{∨}{\textfallback{∨}} \newunicodechar{∧}{\textfallback{∧}} \newunicodechar{⊔}{\textfallback{⊔}} -\newunicodechar{≊}{\textfallback{≊}} +%% \newunicodechar{≊}{\textfallback{≊}} \newunicodechar{∈}{\textfallback{∈}} \newunicodechar{ℂ}{\textfallback{ℂ}} \newunicodechar{∘}{\textfallback{∘}} diff --git a/doc/presentation.tex b/doc/presentation.tex index 95f73fd..85014b6 100644 --- a/doc/presentation.tex +++ b/doc/presentation.tex @@ -1,4 +1,5 @@ \documentclass[a4paper,handout]{beamer} +\usetheme{metropolis} \beamertemplatenavigationsymbolsempty %% \usecolortheme[named=seagull]{structure} @@ -21,28 +22,28 @@ \framesubtitle{Functional extensionality} Consider the functions \begin{align*} - \var{zeroLeft} & \defeq \lambda (n \tp \bN) \mto (0 + n \tp \bN) \\ - \var{zeroRight} & \defeq \lambda (n \tp \bN) \mto (n + 0 \tp \bN) + \var{zeroLeft} & ≜ \lambda (n \tp \bN) \mto (0 + n \tp \bN) \\ + \var{zeroRight} & ≜ \lambda (n \tp \bN) \mto (n + 0 \tp \bN) \end{align*} \pause We have % $$ - \prod_{n \tp \bN} \var{zeroLeft}\ n \equiv \var{zeroRight}\ n + ∏_{n \tp \bN} \var{zeroLeft}\ n ≡ \var{zeroRight}\ n $$ % \pause But not % $$ - \var{zeroLeft} \equiv \var{zeroRight} + \var{zeroLeft} ≡ \var{zeroRight} $$ % \pause We need % $$ - \funExt \tp \prod_{a \tp A} f\ a \equiv g\ a \to f \equiv g + \funExt \tp ∏_{a \tp A} f\ a ≡ g\ a → f ≡ g $$ \end{frame} \begin{frame} @@ -52,20 +53,20 @@ $\{x \mid \phi\ x \land \psi\ x\}$ \pause - If we show $\forall x . \psi\ x \equiv \top$ + If we show $∀ x . \psi\ x ≡ \top$ then we want to conclude - $\{x \mid \phi\ x \land \psi\ x\} \equiv \{x \mid \phi\ x\}$ + $\{x \mid \phi\ x \land \psi\ x\} ≡ \{x \mid \phi\ x\}$ \pause We need univalence: - $$(A \simeq B) \simeq (A \equiv B)$$ + $$(A ≃ B) ≃ (A ≡ B)$$ \pause % - We will return to $\simeq$, but for now think of it as an + We will return to $≃$, but for now think of it as an isomorphism, so it induces maps: \begin{align*} - \var{toPath} & \tp (A \simeq B) \to (A \equiv B) \\ - \var{toEquiv} & \tp (A \equiv B) \to (A \simeq B) + \var{toPath} & \tp (A ≃ B) → (A ≡ B) \\ + \var{toEquiv} & \tp (A ≡ B) → (A ≃ B) \end{align*} \end{frame} \begin{frame} @@ -76,11 +77,11 @@ \Path \tp (P \tp I → \MCU) → P\ 0 → P\ 1 → \MCU \end{equation*} \pause - For $P \tp I \to \MCU$, $A \tp \MCU$ and $a_0, a_1 \tp A$ + For $P \tp I → \MCU$, $A \tp \MCU$ and $a_0, a_1 \tp A$ inhabitants of $\Path\ P\ a_0\ a_1$ are like functions % $$ - p \tp \prod_{i \tp I} P\ i + p \tp ∏_{i \tp I} P\ i $$ % Which satisfy $p\ 0 & = a_0$ and $p\ 1 & = a_1$ @@ -88,46 +89,46 @@ Homogenous paths $$ - a_0 \equiv a_1 \defeq \Path\ (\var{const}\ A)\ a_0\ a_1 + a_0 ≡ a_1 ≜ \Path\ (\var{const}\ A)\ a_0\ a_1 $$ \end{frame} \begin{frame} \frametitle{Paths} \framesubtitle{Functional extenstionality} $$ - \funExt & \tp \prod_{a \tp A} f\ a \equiv g\ a \to f \equiv g + \funExt & \tp ∏_{a \tp A} f\ a ≡ g\ a → f ≡ g $$ \pause $$ - \funExt\ p \defeq λ i\ a → p\ a\ i + \funExt\ p ≜ λ i\ a → p\ a\ i $$ \pause $$ \funExt\ (\var{const}\ \refl) \tp - \var{zeroLeft} \equiv \var{zeroRight} + \var{zeroLeft} ≡ \var{zeroRight} $$ \end{frame} \begin{frame} \frametitle{Paths} \framesubtitle{Homotopy levels} \begin{align*} - & \isContr && \tp \MCU \to \MCU \\ - & \isContr\ A && \defeq \sum_{c \tp A} \prod_{a \tp A} a \equiv c + & \isContr && \tp \MCU → \MCU \\ + & \isContr\ A && ≜ ∑_{c \tp A} ∏_{a \tp A} a ≡ c \end{align*} \pause \begin{align*} - & \isProp && \tp \MCU \to \MCU \\ - & \isProp\ A && \defeq \prod_{a_0, a_1 \tp A} a_0 \equiv a_1 + & \isProp && \tp \MCU → \MCU \\ + & \isProp\ A && ≜ ∏_{a_0, a_1 \tp A} a_0 ≡ a_1 \end{align*} \pause \begin{align*} - & \isSet && \tp \MCU \to \MCU \\ - & \isSet\ A && \defeq \prod_{a_0, a_1 \tp A} \isProp\ (a_0 \equiv a_1) + & \isSet && \tp \MCU → \MCU \\ + & \isSet\ A && ≜ ∏_{a_0, a_1 \tp A} \isProp\ (a_0 ≡ a_1) \end{align*} \begin{align*} - & \isGroupoid && \tp \MCU \to \MCU \\ - & \isGroupoid\ A && \defeq \prod_{a_0, a_1 \tp A} \isSet\ (a_0 \equiv a_1) + & \isGroupoid && \tp \MCU → \MCU \\ + & \isGroupoid\ A && ≜ ∏_{a_0, a_1 \tp A} \isSet\ (a_0 ≡ a_1) \end{align*} \end{frame} \begin{frame} @@ -135,7 +136,7 @@ \framesubtitle{A few lemmas} Let $D$ be a type-family: $$ - D \tp \prod_{b \tp A} \prod_{p \tp a ≡ b} \MCU + D \tp ∏_{b \tp A} ∏_{p \tp a ≡ b} \MCU $$ % \pause @@ -149,7 +150,7 @@ We then have the function: % $$ - \pathJ\ D\ d \tp \prod_{b \tp A} \prod_{p \tp a ≡ b} D\ b\ p + \pathJ\ D\ d \tp ∏_{b \tp A} ∏_{p \tp a ≡ b} D\ b\ p $$ \end{frame} \begin{frame} @@ -158,9 +159,9 @@ Given \begin{align*} A & \tp \MCU \\ - P & \tp A \to \MCU \\ - \var{propP} & \tp \prod_{x \tp A} \isProp\ (P\ x) \\ - p & \tp a_0 \equiv a_1 \\ + P & \tp A → \MCU \\ + \var{propP} & \tp ∏_{x \tp A} \isProp\ (P\ x) \\ + p & \tp a_0 ≡ a_1 \\ p_0 & \tp P\ a_0 \\ p_1 & \tp P\ a_1 \end{align*} @@ -176,17 +177,17 @@ \begin{frame} \frametitle{Paths} \framesubtitle{A few lemmas} - $\prod$ preserves $\isProp$: + $∏$ preserves $\isProp$: $$ \mathit{propPi} \tp - \left(\prod_{a \tp A} \isProp\ (P\ a)\right) - \to \isProp\ \left(\prod_{a \tp A} P\ a\right) + \left(∏_{a \tp A} \isProp\ (P\ a)\right) + → \isProp\ \left(∏_{a \tp A} P\ a\right) $$ \pause - $\sum$ preserves $\isProp$: + $∑$ preserves $\isProp$: $$ - \mathit{propSig} \tp \isProp\ A \to \left(\prod_{a \tp A} \isProp\ (P\ a)\right) \to \isProp\ \left(\sum_{a \tp A} P\ a\right) + \mathit{propSig} \tp \isProp\ A → \left(∏_{a \tp A} \isProp\ (P\ a)\right) → \isProp\ \left(∑_{a \tp A} P\ a\right) $$ \end{frame} \begin{frame} @@ -195,9 +196,9 @@ Data: \begin{align*} \Object & \tp \Type \\ - \Arrow & \tp \Object \to \Object \to \Type \\ + \Arrow & \tp \Object → \Object → \Type \\ \identity & \tp \Arrow\ A\ A \\ - \lll & \tp \Arrow\ B\ C \to \Arrow\ A\ B \to \Arrow\ A\ C + \lll & \tp \Arrow\ B\ C → \Arrow\ A\ B → \Arrow\ A\ C \end{align*} % \pause @@ -208,7 +209,7 @@ $$ $$ (\identity \lll f ≡ f) - \x + × (f \lll \identity ≡ f) $$ \pause @@ -221,7 +222,7 @@ \frametitle{Pre categories} \framesubtitle{Propositionality} $$ - \isProp\ \left( (\identity \comp f \equiv f) \x (f \comp \identity \equiv f) \right) + \isProp\ \left( (\identity \comp f ≡ f) × (f \comp \identity ≡ f) \right) $$ \pause \begin{align*} @@ -247,14 +248,17 @@ \frametitle{Categories} \framesubtitle{Univalence} \begin{align*} - \var{IsIdentity} & \defeq - \prod_{A\ B \tp \Object} \prod_{f \tp \Arrow\ A\ B} \phi\ f + \var{IsIdentity} & ≜ + ∏_{A\ B \tp \Object} ∏_{f \tp \Arrow\ A\ B} \phi\ f %% \\ - %% & \mathrel{\ } \identity \lll f \equiv f \x f \lll \identity \equiv f + %% & \mathrel{\ } \identity \lll f ≡ f × f \lll \identity ≡ f \end{align*} where $$ - \phi\ f \defeq \identity \lll f \equiv f \x f \lll \identity \equiv f + \phi\ f ≜ \identity + ( \lll f ≡ f ) + × + ( f \lll \identity ≡ f) $$ \pause Let $\approxeq$ denote ismorphism of objects. We can then construct @@ -271,29 +275,29 @@ For a category to be univalent we require this to be an equivalence: % $$ - \isEquiv\ (A \equiv B)\ (A \approxeq B)\ \idToIso + \isEquiv\ (A ≡ B)\ (A \approxeq B)\ \idToIso $$ % \end{frame} \begin{frame} \frametitle{Categories} \framesubtitle{Univalence, cont'd} - $$\isEquiv\ (A \equiv B)\ (A \approxeq B)\ \idToIso$$ + $$\isEquiv\ (A ≡ B)\ (A \approxeq B)\ \idToIso$$ \pause% - $$(A \equiv B) \simeq (A \approxeq B)$$ + $$(A ≡ B) ≃ (A \approxeq B)$$ \pause% - $$(A \equiv B) \cong (A \approxeq B)$$ + $$(A ≡ B) ≅ (A \approxeq B)$$ \pause% Name the above maps: $$\idToIso \tp A ≡ B → A ≊ B$$ % - $$\isoToId \tp (A \approxeq B) \to (A \equiv B)$$ + $$\isoToId \tp (A \approxeq B) → (A ≡ B)$$ \end{frame} \begin{frame} \frametitle{Categories} \framesubtitle{Propositionality} $$ - \isProp\ \IsCategory = \prod_{a, b \tp \IsCategory} a \equiv b + \isProp\ \IsCategory = ∏_{a, b \tp \IsCategory} a ≡ b $$ \pause So, for @@ -303,8 +307,8 @@ the proof obligation is the pair: % \begin{align*} - p & \tp a.\isPreCategory \equiv b.\isPreCategory \\ - & \mathrel{\ } \Path\ (\lambda\; i \to (p\ i).Univalent)\ a.\isPreCategory\ b.\isPreCategory + p & \tp a.\isPreCategory ≡ b.\isPreCategory \\ + & \mathrel{\ } \Path\ (\lambda\; i → (p\ i).Univalent)\ a.\isPreCategory\ b.\isPreCategory \end{align*} \end{frame} \begin{frame} @@ -313,17 +317,17 @@ First path given by: $$ p - \defeq + ≜ \var{propIsPreCategory}\ a\ b \tp - a.\isPreCategory \equiv b.\isPreCategory + a.\isPreCategory ≡ b.\isPreCategory $$ \pause Use $\lemPropF$ for the latter. \pause % - Univalence is indexed by an identity proof. So $A \defeq - IsIdentity\ identity$ and $B \defeq \var{Univalent}$. + Univalence is indexed by an identity proof. So $A ≜ + IsIdentity\ identity$ and $B ≜ \var{Univalent}$. \pause % $$ @@ -342,16 +346,16 @@ The isomorphism induces the path % $$ - p \defeq \idToIso\ (\iota, \inv{\iota}) \tp A \equiv B + p ≜ \idToIso\ (\iota, \inv{\iota}) \tp A ≡ B $$ % \pause and consequently an arrow: % $$ - p_{\var{dom}} \defeq \congruence\ (λ x → \Arrow\ x\ X)\ p + p_{\var{dom}} ≜ \congruence\ (λ x → \Arrow\ x\ X)\ p \tp - \Arrow\ A\ X \equiv \Arrow\ B\ X + \Arrow\ A\ X ≡ \Arrow\ B\ X $$ % \pause @@ -360,8 +364,8 @@ \begin{align} \label{eq:coeDom} \tag{$\var{coeDom}$} - \prod_{f \tp A \to X} - \var{coe}\ p_{\var{dom}}\ f \equiv f \lll \inv{\iota} + ∏_{f \tp A → X} + \var{coe}\ p_{\var{dom}}\ f ≡ f \lll \inv{\iota} \end{align} \end{frame} \begin{frame} @@ -369,23 +373,23 @@ \framesubtitle{A theorem, proof} \begin{align*} \var{coe}\ p_{\var{dom}}\ f - & \equiv f \lll \inv{(\idToIso\ p)} && \text{By path-induction} \\ - & \equiv f \lll \inv{\iota} + & ≡ f \lll \inv{(\idToIso\ p)} && \text{By path-induction} \\ + & ≡ f \lll \inv{\iota} && \text{$\idToIso$ and $\isoToId$ are inverses}\\ \end{align*} \pause % Induction will be based at $A$. Let $\widetilde{B}$ and $\widetilde{p} - \tp A \equiv \widetilde{B}$ be given. + \tp A ≡ \widetilde{B}$ be given. % \pause % Define the family: % $$ - D\ \widetilde{B}\ \widetilde{p} \defeq + D\ \widetilde{B}\ \widetilde{p} ≜ \var{coe}\ \widetilde{p}_{\var{dom}}\ f - \equiv + ≡ f \lll \inv{(\idToIso\ \widetilde{p})} $$ \pause @@ -393,7 +397,7 @@ The base-case becomes: $$ d \tp D\ A\ \refl = - \var{coe}\ \refl_{\var{dom}}\ f \equiv f \lll \inv{(\idToIso\ \refl)} + \var{coe}\ \refl_{\var{dom}}\ f ≡ f \lll \inv{(\idToIso\ \refl)} $$ \end{frame} \begin{frame} @@ -401,17 +405,17 @@ \framesubtitle{A theorem, proof, cont'd} $$ d \tp - \var{coe}\ \refl_{\var{dom}}\ f \equiv f \lll \inv{(\idToIso\ \refl)} + \var{coe}\ \refl_{\var{dom}}\ f ≡ f \lll \inv{(\idToIso\ \refl)} $$ \pause \begin{align*} \var{coe}\ \refl^*\ f - & \equiv f + & ≡ f && \text{$\refl$ is a neutral element for $\var{coe}$}\\ - & \equiv f \lll \identity \\ - & \equiv f \lll \var{subst}\ \refl\ \identity + & ≡ f \lll \identity \\ + & ≡ f \lll \var{subst}\ \refl\ \identity && \text{$\refl$ is a neutral element for $\var{subst}$}\\ - & \equiv f \lll \inv{(\idToIso\ \refl)} + & ≡ f \lll \inv{(\idToIso\ \refl)} && \text{By definition of $\idToIso$}\\ \end{align*} \pause @@ -429,7 +433,7 @@ \pause Objects: $$ - \sum_{X \tp Object} \Arrow\ X\ \pairA × \Arrow\ X\ \pairB + ∑_{X \tp Object} \Arrow\ X\ \pairA × \Arrow\ X\ \pairB $$ \pause % @@ -437,9 +441,9 @@ $B ,\ b_{\pairA} ,\ b_{\pairB}$: % $$ - \sum_{f \tp \Arrow\ A\ B} - b_{\pairA} \lll f \equiv a_{\pairA} \x - b_{\pairB} \lll f \equiv a_{\pairB} + ∑_{f \tp \Arrow\ A\ B} + b_{\pairA} \lll f ≡ a_{\pairA} × + b_{\pairB} \lll f ≡ a_{\pairB} $$ \end{frame} \begin{frame} @@ -447,25 +451,25 @@ \framesubtitle{Univalence} \begin{align*} \label{eq:univ-0} - (X , x_{\mathcal{A}} , x_{\mathcal{B}}) ≡ (Y , y_{\mathcal{A}} , y_{\mathcal{B}}) + (X , x_{𝒜} , x_{ℬ}) ≡ (Y , y_{𝒜} , y_{ℬ}) \end{align*} \begin{align*} \label{eq:univ-1} \begin{split} - p \tp & X \equiv Y \\ - & \Path\ (λ i → \Arrow\ (p\ i)\ \mathcal{A})\ x_{\mathcal{A}}\ y_{\mathcal{A}} \\ - & \Path\ (λ i → \Arrow\ (p\ i)\ \mathcal{B})\ x_{\mathcal{B}}\ y_{\mathcal{B}} + p \tp & X ≡ Y \\ + & \Path\ (λ i → \Arrow\ (p\ i)\ 𝒜)\ x_{𝒜}\ y_{𝒜} \\ + & \Path\ (λ i → \Arrow\ (p\ i)\ ℬ)\ x_{ℬ}\ y_{ℬ} \end{split} \end{align*} \begin{align*} \begin{split} \var{iso} \tp & X \approxeq Y \\ - & \Path\ (λ i → \Arrow\ (\widetilde{p}\ i)\ \mathcal{A})\ x_{\mathcal{A}}\ y_{\mathcal{A}} \\ - & \Path\ (λ i → \Arrow\ (\widetilde{p}\ i)\ \mathcal{B})\ x_{\mathcal{B}}\ y_{\mathcal{B}} + & \Path\ (λ i → \Arrow\ (\widetilde{p}\ i)\ 𝒜)\ x_{𝒜}\ y_{𝒜} \\ + & \Path\ (λ i → \Arrow\ (\widetilde{p}\ i)\ ℬ)\ x_{ℬ}\ y_{ℬ} \end{split} \end{align*} \begin{align*} - (X , x_{\mathcal{A}} , x_{\mathcal{B}}) ≊ (Y , y_{\mathcal{A}} , y_{\mathcal{B}}) + (X , x_{𝒜} , x_{ℬ}) ≊ (Y , y_{𝒜} , y_{ℬ}) \end{align*} \end{frame} \begin{frame} @@ -475,12 +479,12 @@ \begin{align*} %% (f, \inv{f}, \var{inv}_f, \var{inv}_{\inv{f}}) %% \tp - (X, x_{\mathcal{A}}, x_{\mathcal{B}}) \approxeq (Y, y_{\mathcal{A}}, y_{\mathcal{B}}) + (X, x_{𝒜}, x_{ℬ}) \approxeq (Y, y_{𝒜}, y_{ℬ}) \to \begin{split} \var{iso} \tp & X \approxeq Y \\ - & \Path\ (λ i → \Arrow\ (\widetilde{p}\ i)\ \mathcal{A})\ x_{\mathcal{A}}\ y_{\mathcal{A}} \\ - & \Path\ (λ i → \Arrow\ (\widetilde{p}\ i)\ \mathcal{B})\ x_{\mathcal{B}}\ y_{\mathcal{B}} + & \Path\ (λ i → \Arrow\ (\widetilde{p}\ i)\ 𝒜)\ x_{𝒜}\ y_{𝒜} \\ + & \Path\ (λ i → \Arrow\ (\widetilde{p}\ i)\ ℬ)\ x_{ℬ}\ y_{ℬ} \end{split} \end{align*} \pause @@ -503,8 +507,8 @@ % \begin{align*} \begin{split} - \widetilde{p} & \tp X \equiv Y \\ - \widetilde{p}_{\mathcal{A}} & \tp \Arrow\ X\ \mathcal{A} \equiv \Arrow\ Y\ \mathcal{A} \\ + \widetilde{p} & \tp X ≡ Y \\ + \widetilde{p}_{𝒜} & \tp \Arrow\ X\ 𝒜 ≡ \Arrow\ Y\ 𝒜 \\ \end{split} \end{align*} % @@ -517,7 +521,7 @@ \begin{align*} \begin{split} \label{eq:product-paths} - & \Path\ (λ i → \widetilde{p}_{\mathcal{A}}\ i)\ x_{\mathcal{A}}\ y_{\mathcal{A}} + & \Path\ (λ i → \widetilde{p}_{𝒜}\ i)\ x_{𝒜}\ y_{𝒜} \end{split} \end{align*} \pause @@ -525,9 +529,9 @@ This is achieved with the following lemma: % \begin{align*} - \prod_{q \tp A \equiv B} \var{coe}\ q\ x_{\mathcal{A}} ≡ y_{\mathcal{A}} + ∏_{q \tp A ≡ B} \var{coe}\ q\ x_{𝒜} ≡ y_{𝒜} → - \Path\ (λ i → q\ i)\ x_{\mathcal{A}}\ y_{\mathcal{A}} + \Path\ (λ i → q\ i)\ x_{𝒜}\ y_{𝒜} \end{align*} % Which is used without proof.\pause @@ -535,15 +539,15 @@ So the construction reduces to: % \begin{align*} - \var{coe}\ \widetilde{p}_{\mathcal{A}}\ x_{\mathcal{A}} ≡ y_{\mathcal{A}} + \var{coe}\ \widetilde{p}_{𝒜}\ x_{𝒜} ≡ y_{𝒜} \end{align*}% \pause% This is proven with: % \begin{align*} - \var{coe}\ \widetilde{p}_{\mathcal{A}}\ x_{\mathcal{A}} - & ≡ x_{\mathcal{A}} \lll \fst\ \inv{f} && \text{\ref{eq:coeDom}} \\ - & ≡ y_{\mathcal{A}} && \text{Property of span category} + \var{coe}\ \widetilde{p}_{𝒜}\ x_{𝒜} + & ≡ x_{𝒜} \lll \fst\ \inv{f} && \text{\ref{eq:coeDom}} \\ + & ≡ y_{𝒜} && \text{Property of span category} \end{align*} \end{frame} \begin{frame} @@ -556,13 +560,13 @@ % We can show: \begin{align*} - \var{Terminal} ≃ \var{Product}\ ℂ\ \mathcal{A}\ \mathcal{B} + \var{Terminal} ≃ \var{Product}\ ℂ\ 𝒜\ ℬ \end{align*} \pause And since equivalences preserve homotopy levels we get: % $$ - \isProp\ \left(\var{Product}\ \bC\ \mathcal{A}\ \mathcal{B}\right) + \isProp\ \left(\var{Product}\ \bC\ 𝒜\ ℬ\right) $$ \end{frame} \begin{frame} @@ -595,7 +599,7 @@ % \begin{align*} \omapR & \tp \Object → \Object \\ - \pure & \tp % \prod_{X \tp Object} + \pure & \tp % ∏_{X \tp Object} \Arrow\ X\ (\omapR\ X) \\ \bind & \tp \Arrow\ X\ (\omapR\ Y) @@ -610,7 +614,7 @@ \Arrow\ B\ (\omapR\ C) → \Arrow\ A\ (\omapR\ C) \\ - f \fish g & \defeq f \rrr (\bind\ g) + f \fish g & ≜ f \rrr (\bind\ g) \end{align*} \pause % @@ -629,20 +633,20 @@ In the monoidal formulation we can define $\bind$: % $$ - \bind\ f \defeq \join \lll \fmap\ f + \bind\ f ≜ \join \lll \fmap\ f $$ \pause % And likewise in the Kleisli formulation we can define $\join$: % $$ - \join \defeq \bind\ \identity + \join ≜ \bind\ \identity $$ \pause The laws are logically equivalent. So we get: % $$ - \var{Monoidal} \simeq \var{Kleisli} + \var{Monoidal} ≃ \var{Kleisli} $$ % \end{frame} From b992d5a7f2b4a619f624c6eb75bf6d6cf36d1c50 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frederik=20Hangh=C3=B8j=20Iversen?= Date: Mon, 28 May 2018 17:42:00 +0200 Subject: [PATCH 29/33] Use unicode symbols --- doc/implementation.tex | 370 ++++++++++++++++++++--------------------- 1 file changed, 185 insertions(+), 185 deletions(-) diff --git a/doc/implementation.tex b/doc/implementation.tex index ad2ed63..51f5629 100644 --- a/doc/implementation.tex +++ b/doc/implementation.tex @@ -112,13 +112,13 @@ definitions: If we let $p$ be a witness to the identity law, which formally is: % \begin{equation} \label{eq:identity} - \var{IsIdentity} \defeq - \prod_{A, B \tp \Object} \prod_{f \tp \Arrow\ A\ B} - \left(\id \lll f \equiv f\right) \x \left(f \lll \id \equiv f\right) + \var{IsIdentity} ≜ + ∏_{A, B \tp \Object} ∏_{f \tp \Arrow\ A\ B} + \left(\id \lll f ≡ f\right) \x \left(f \lll \id ≡ f\right) \end{equation} % Then we can construct the identity isomorphism $\idIso \tp (\identity, -\identity, p) \tp A \approxeq A$ for any object $A$. Here $\approxeq$ +\identity, p) \tp A ≊ A$ for any object $A$. Here $≊$ denotes isomorphism on objects (whereas $\cong$ denotes isomorphism on types). This will be elaborated further on in sections \S\ref{sec:equiv} and \S\ref{sec:univalence}. Moreover due to @@ -135,7 +135,7 @@ isomorphism on objects play the role of equivalence on types. Formally: % \begin{align} \label{eq:cat-univ} -\isEquiv\ (A \equiv B)\ (A \approxeq B)\ \idToIso +\isEquiv\ (A ≡ B)\ (A ≊ B)\ \idToIso \end{align} % Note that \ref{eq:cat-univ} is \emph{not} the same as: @@ -143,7 +143,7 @@ Note that \ref{eq:cat-univ} is \emph{not} the same as: \begin{equation} \label{eq:cat-univalence} %% \tag{Univalence, category} -(A \equiv B) \simeq (A \approxeq B) +(A ≡ B) ≃ (A ≊ B) \end{equation} % However the two are logically equivalent: One can construct the latter @@ -156,9 +156,9 @@ data: % \begin{align} \Object & \tp \Type \\ - \Arrow & \tp \Object \to \Object \to \Type \\ + \Arrow & \tp \Object → \Object → \Type \\ \identity & \tp \Arrow\ A\ A \\ - \lll & \tp \Arrow\ B\ C \to \Arrow\ A\ B \to \Arrow\ A\ C + \lll & \tp \Arrow\ B\ C → \Arrow\ A\ B → \Arrow\ A\ C \end{align} % And laws: @@ -179,7 +179,7 @@ f \lll \identity ≡ f %% \tag{arrows are sets} \isSet\ (\Arrow\ A\ B)\\ \tag{\ref{eq:cat-univ}} -\isEquiv\ (A \equiv B)\ (A \approxeq B)\ \idToIso +\isEquiv\ (A ≡ B)\ (A ≊ B)\ \idToIso \end{align} % $\lll$ denotes arrow composition (right-to-left), and reverse function @@ -205,25 +205,25 @@ is by way of the `combinators' $\propPi$ and $\propSig$ presented in sections \S\ref{sec:propPi} and \S\ref{sec:propSig}: % \begin{align*} -\propPi & \tp \left(\prod_{a \tp A} \isProp\ (P\ a)\right) \to \isProp\ \left(\prod_{a \tp A} P\ a\right) +\propPi & \tp \left(∏_{a \tp A} \isProp\ (P\ a)\right) → \isProp\ \left(∏_{a \tp A} P\ a\right) \\ -\propSig & \tp \isProp\ A \to \left(\prod_{a \tp A} \isProp\ (P\ a)\right) \to \isProp\ \left(\sum_{a \tp A} P\ a\right) +\propSig & \tp \isProp\ A → \left(∏_{a \tp A} \isProp\ (P\ a)\right) → \isProp\ \left(∑_{a \tp A} P\ a\right) \end{align*} % The proof goes like this: We `eliminate' the 3 function abstractions by applying $\propPi$ three times. So our proof obligation becomes: % $$ -\isProp\ \left( \left( \id \comp f \equiv f \right) \x \left( f \comp \id \equiv f \right) \right) +\isProp\ \left( \left( \id \comp f ≡ f \right) \x \left( f \comp \id ≡ f \right) \right) $$ % Then we eliminate the (non-dependent) sigma-type by applying $\propSig$ giving -us the two obligations $\isProp\ (\id \comp f \equiv f)$ and $\isProp\ (f \comp -\id \equiv f)$ which follows from the type of arrows being a +us the two obligations $\isProp\ (\id \comp f ≡ f)$ and $\isProp\ (f \comp +\id ≡ f)$ which follows from the type of arrows being a set. This example illustrates nicely how we can use these combinators to -reason about `canonical' types like $\sum$ and $\prod$. Similar +reason about `canonical' types like $∑$ and $∏$. Similar combinators can be defined at the other homotopic levels. These combinators are however not applicable in situations where we want to reason about other types e.g.\ types we have defined ourselves. For @@ -236,7 +236,7 @@ show that the type of pre-categories is also a proposition. Formally: \isProp\ \IsPreCategory \end{equation} % -Where The definition of $\IsPreCategory$ is the triple: +Where the definition of $\IsPreCategory$ is the triple: % \begin{align*} \var{isAssociative} & \tp \var{IsAssociative}\\ @@ -252,12 +252,12 @@ the path type must be used directly. The type \ref{eq:propIsPreCategory} is judgmentally the same as: % $$ -\prod_{a, b \tp \IsPreCategory} a \equiv b +∏_{a, b \tp \IsPreCategory} a ≡ b $$ % So to prove the proposition let $a, b \tp \IsPreCategory$ be given. To -prove the equality $a \equiv b$ is to give a continuous path from the -index-type into the path-space. I.e.\ a function $\I \to +prove the equality $a ≡ b$ is to give a continuous path from the +index-type into the path-space. I.e.\ a function $\I → \IsPreCategory$. This path must satisfy being being judgmentally the same as $a$ at the left endpoint and $b$ at the right endpoint. We know we can form a continuous path between all projections of $a$ and @@ -268,14 +268,14 @@ $b.\isIdentity$ is simply formed by: $$ \propIsIdentity\ a.\isIdentity\ b.\isIdentity \tp -a.\isIdentity \equiv b.\isIdentity +a.\isIdentity ≡ b.\isIdentity $$ % -So to give the continuous function $\I \to \IsPreCategory$, which is our goal, we +So to give the continuous function $\I → \IsPreCategory$, which is our goal, we introduce $i \tp \I$ and proceed by constructing an element of $\IsPreCategory$ by using the fact that all the projections are propositions to generate paths between all projections. Once we have such a path e.g.\ $p \tp a.\isIdentity -\equiv b.\isIdentity$ we can eliminate it with $i$ and thus obtain $p\ i \tp +≡ b.\isIdentity$ we can eliminate it with $i$ and thus obtain $p\ i \tp (p\ i).\isIdentity$. This element satisfies exactly that it corresponds to the corresponding projections at either endpoint. Thus the element we construct at $i$ becomes the triple: @@ -298,7 +298,7 @@ equalities at different levels. It is worth noting that proving this theorem with the regular inductive equality type would already not be possible, since we at least need functional extensionality\index{functional extensionality} (the projections are -all $\prod$-types). Assuming we had functional extensionality +all $∏$-types). Assuming we had functional extensionality available to us as an axiom, we would use functional extensionality \TODO{in reverse?} to retrieve the equalities in $a$ and $b$, pattern-match on them to see that they are both $\refl$ and then close @@ -315,13 +315,13 @@ follow the same recipe as above, let $a, b \tp \IsCategory$ be given, to show them equal, we now need to give two paths. One homogeneous: % $$ -p \tp a.\isPreCategory \equiv b.\isPreCategory +p \tp a.\isPreCategory ≡ b.\isPreCategory $$ % and one heterogeneous: % $$ -\Path\ (\lambda\; i \to (p\ i).Univalent)\ a.\isPreCategory\ b.\isPreCategory +\Path\ (\lambda\; i → (p\ i).Univalent)\ a.\isPreCategory\ b.\isPreCategory $$ % Which depends on the choice of $p$. The first of these we can provide since, as @@ -349,7 +349,7 @@ When we have a proper category we can make precise the notion of function: % $$ -\isoToId \tp (A \approxeq B) \to (A \equiv B) +\isoToId \tp (A ≊ B) → (A ≡ B) $$ % A perhaps somewhat surprising application of this is that we can show that @@ -371,11 +371,11 @@ details. It is in the module: \section{Equivalences} \label{sec:equiv} -The usual notion of a function $f \tp A \to B$ having an inverses is: +The usual notion of a function $f \tp A → B$ having an inverses is: % \begin{equation} \label{eq:isomorphism} -\sum_{g \tp B \to A} \left( f \comp g \equiv \identity \right) \x \left( g \comp f \equiv \identity \right) +∑_{g \tp B → A} \left( f \comp g ≡ \identity \right) \x \left( g \comp f ≡ \identity \right) \end{equation} % This is defined in \cite[p. 129]{hott-2013} where it is referred to as the a @@ -383,15 +383,15 @@ This is defined in \cite[p. 129]{hott-2013} where it is referred to as the a $\Isomorphism\ f$. This also gives rise to the following type: % \begin{equation} -A \cong B \defeq \sum_{f \tp A \to B} \Isomorphism\ f +A \cong B ≜ ∑_{f \tp A → B} \Isomorphism\ f \end{equation} % At the same place \cite{hott-2013} gives an ``interface'' for what the judgment -$\isEquiv \tp (A \to B) \to \MCU$ must provide: +$\isEquiv \tp (A → B) → \MCU$ must provide: % \begin{align} -\var{fromIso} & \tp \Isomorphism\ f \to \isEquiv\ f \\ -\var{toIso} & \tp \isEquiv\ f \to \Isomorphism\ f \\ +\var{fromIso} & \tp \Isomorphism\ f → \isEquiv\ f \\ +\var{toIso} & \tp \isEquiv\ f → \Isomorphism\ f \\ \label{eq:propIsEquiv} &\mathrel{\ } \isEquiv\ f \end{align} @@ -399,8 +399,8 @@ $\isEquiv \tp (A \to B) \to \MCU$ must provide: The maps $\var{fromIso}$ and $\var{toIso}$ naturally extend to these maps: % \begin{align} -\var{fromIsomorphism} & \tp A \cong B \to A \simeq B \\ -\var{toIsomorphism} & \tp A \simeq B \to A \cong B +\var{fromIsomorphism} & \tp A \cong B → A ≃ B \\ +\var{toIsomorphism} & \tp A ≃ B → A \cong B \end{align} % Having this interface gives us both: a way to think rather abstractly about how @@ -408,11 +408,11 @@ to work with equivalences and a way to use ad hoc definitions of equivalences. The specific instantiation of $\isEquiv$ as defined in \cite{cubical-agda} is: % $$ -isEquiv\ f \defeq \prod_{b \tp B} \isContr\ (\fiber\ f\ b) +isEquiv\ f ≜ ∏_{b \tp B} \isContr\ (\fiber\ f\ b) $$ where $$ -\fiber\ f\ b \defeq \sum_{a \tp A} \left( b \equiv f\ a \right) +\fiber\ f\ b ≜ ∑_{a \tp A} \left( b ≡ f\ a \right) $$ % I give its definition here mainly for completeness, because as I stated we can @@ -430,16 +430,16 @@ equivalence between them: % \begin{equation} \label{eq:equivalence} -A \simeq B \defeq \sum_{f \tp A \to B} \isEquiv\ f +A ≃ B ≜ ∑_{f \tp A → B} \isEquiv\ f \end{equation} % Note that the term equivalence here is overloaded referring both to the map $f -\tp A \to B$ and the type $A \simeq B$. The notion of an isomorphism is +\tp A → B$ and the type $A ≃ B$. The notion of an isomorphism is similarly conflated as isomorphism can refer to the type $A \cong B$ as well as -the the map $A \to B$ that witness this. I will use these conflated terms when +the the map $A → B$ that witness this. I will use these conflated terms when it is clear from the context what is being referred to. -Both $\cong$ and $\simeq$ form equivalence relations (no pun intended). +Both $\cong$ and $≃$ form equivalence relations (no pun intended). \section{Univalence} \label{sec:univalence} @@ -447,25 +447,25 @@ As noted in the introduction the univalence for types $A\; B \tp \Type$ states that: % $$ -\var{Univalence} \defeq (A \equiv B) \simeq (A \simeq B) +\var{Univalence} ≜ (A ≡ B) ≃ (A ≃ B) $$ % As mentioned the univalence criterion for some category $\bC$ says that for all \emph{objects} $A\;B$ we must have: $$ -\isEquiv\ (A \equiv B)\ (A \approxeq B)\ \idToIso +\isEquiv\ (A ≡ B)\ (A ≊ B)\ \idToIso $$ And I mentioned that this was logically equivalent to % $$ -(A \equiv B) \simeq (A \approxeq B) +(A ≡ B) ≃ (A ≊ B) $$ % Given that we saw in the previous section that we can construct an equivalence from an isomorphism it suffices to demonstrate: % $$ -(A \equiv B) \cong (A \approxeq B) +(A ≡ B) \cong (A ≊ B) $$ % That is, we must demonstrate that there is an isomorphism (on types) between @@ -480,87 +480,87 @@ to behave similarly to maps. I will now mention a few helpful theorems that follow from univalence that will become useful later. -Obviously univalence gives us an isomorphism between $A \equiv B$ and $A -\approxeq B$. I will name these for convenience: +Obviously univalence gives us an isomorphism between $A ≡ B$ and $A +≊ B$. I will name these for convenience: % $$ -\idToIso \tp A \equiv B \to A \approxeq B +\idToIso \tp A ≡ B → A ≊ B $$ % $$ -\isoToId \tp A \approxeq B \to A \equiv B +\isoToId \tp A ≊ B → A ≡ B $$ % The next few theorems are variations on theorem 9.1.9 from \cite{hott-2013}. Let -an isomorphism $A \approxeq B$ in some category $\bC$ be given. Name the -isomorphism $\iota \tp A \to B$ and its inverse $\inv{\iota} \tp B \to A$. +an isomorphism $A ≊ B$ in some category $\bC$ be given. Name the +isomorphism $\iota \tp A → B$ and its inverse $\inv{\iota} \tp B → A$. Since $\bC$ is a category (and therefore univalent) the isomorphism induces a -path $p \tp A \equiv B$. From this equality we can get two further paths: -$p_{\var{dom}} \tp \Arrow\ A\ X \equiv \Arrow\ B\ X$ and -$p_{\var{cod}} \tp \Arrow\ X\ A \equiv \Arrow\ X\ B$. We +path $p \tp A ≡ B$. From this equality we can get two further paths: +$p_{\var{dom}} \tp \Arrow\ A\ X ≡ \Arrow\ B\ X$ and +$p_{\var{cod}} \tp \Arrow\ X\ A ≡ \Arrow\ X\ B$. We then have the following two theorems: % \begin{align} \label{eq:coeDom} -\var{coeDom} & \tp \prod_{f \tp A \to X} -\var{coe}\ p_{\var{dom}}\ f \equiv f \lll \inv{\iota} +\var{coeDom} & \tp ∏_{f \tp A → X} +\var{coe}\ p_{\var{dom}}\ f ≡ f \lll \inv{\iota} \\ \label{eq:coeCod} -\var{coeCod} & \tp \prod_{f \tp A \to X} -\var{coe}\ p_{\var{cod}}\ f \equiv \iota \lll f +\var{coeCod} & \tp ∏_{f \tp A → X} +\var{coe}\ p_{\var{cod}}\ f ≡ \iota \lll f \end{align} % I will give the proof of the first theorem here, the second one is analogous. % \begin{align*} \var{coe}\ p_{\var{dom}}\ f - & \equiv f \lll \inv{(\idToIso\ p)} && \text{lemma} \\ - & \equiv f \lll \inv{\iota} + & ≡ f \lll \inv{(\idToIso\ p)} && \text{lemma} \\ + & ≡ f \lll \inv{\iota} && \text{$\idToIso$ and $\isoToId$ are inverses}\\ \end{align*} % In the second step we use the fact that $p$ is constructed from the isomorphism -$\iota$ -- $\inv{(\idToIso\ p)}$ denotes the map $B \to A$ induced by the +$\iota$ -- $\inv{(\idToIso\ p)}$ denotes the map $B → A$ induced by the isomorphism $\idToIso\ p \tp A \cong B$. The helper-lemma is similar to what we are trying to prove but talks about paths rather than isomorphisms: % \begin{equation} \label{eq:coeDomIso} -\prod_{f \tp \Arrow\ A\ B} \prod_{p \tp A \equiv B} -\var{coe}\ p_{\var{dom}}\ f \equiv f \lll \inv{(\idToIso\ p)} +∏_{f \tp \Arrow\ A\ B} ∏_{p \tp A ≡ B} +\var{coe}\ p_{\var{dom}}\ f ≡ f \lll \inv{(\idToIso\ p)} \end{equation} % -Again $p_{\var{dom}}$ denotes the path $\Arrow\ A\ X \equiv +Again $p_{\var{dom}}$ denotes the path $\Arrow\ A\ X ≡ \Arrow\ B\ X$ induced by $p$. To prove this statement I let $f$ and $p$ be given and then invoke based-path-induction. The induction will be based at $A \tp \Object$ Let $\widetilde{B} \tp \Object$ and $\widetilde{p} \tp A -\equiv \widetilde{B}$ be given. The family that we perform induction over will +≡ \widetilde{B}$ be given. The family that we perform induction over will be: % \begin{align} -D\ \widetilde{B}\ \widetilde{p} \defeq - %% \prod_{\widetilde{B} \tp \Object} - %% \prod_{\widetilde{p} \tp A \equiv \widetilde{B}} +D\ \widetilde{B}\ \widetilde{p} ≜ + %% ∏_{\widetilde{B} \tp \Object} + %% ∏_{\widetilde{p} \tp A ≡ \widetilde{B}} \var{coe}\ {\widetilde{p}}^*\ f -\equiv +≡ f \lll \inv{(\idToIso\ \widetilde{p})} \end{align} The base-case therefore becomes -$d \tp \var{coe}\ \refl^*\ f \equiv f \lll \inv{(\idToIso\ \refl)}$ +$d \tp \var{coe}\ \refl^*\ f ≡ f \lll \inv{(\idToIso\ \refl)}$ and is inhabited by: \begin{align*} \var{coe}\ \refl^*\ f -& \equiv f +& ≡ f && \text{$\refl$ is a neutral element for $\var{coe}$}\\ -& \equiv f \lll \identity \\ -& \equiv f \lll \var{subst}\ \refl\ \identity +& ≡ f \lll \identity \\ +& ≡ f \lll \var{subst}\ \refl\ \identity && \text{$\refl$ is a neutral element for $\var{subst}$}\\ -& \equiv f \lll \inv{(\idToIso\ \refl)} +& ≡ f \lll \inv{(\idToIso\ \refl)} && \text{By definition of $\idToIso$}\\ \end{align*} % To close the based-path-induction we must supply the value ``at the other''. In -this case this is simply $B \tp \Object$ and $p \tp A \equiv B$ which we have. +this case this is simply $B \tp \Object$ and $p \tp A ≡ B$ which we have. In summary the proof of \ref{eq:coeDomIso} is the term: % \begin{equation} @@ -594,14 +594,14 @@ category. Showing that this forms a pre-category is rather straightforward. % $$ -h \rrr (g \rrr f) \equiv h \rrr g \rrr f +h \rrr (g \rrr f) ≡ h \rrr g \rrr f $$ % Since $\rrr$ is reverse function composition this is just the symmetric version of associativity. % $$ -\identity \rrr f \equiv f \x f \rrr identity \equiv f +\identity \rrr f ≡ f \x f \rrr \identity ≡ f $$ % This is just the swapped version of identity. @@ -613,21 +613,21 @@ arguments. Or in other words; since $\Arrow\ A\ B$ is a set for all $A\;B \tp Now, to show that this category is univalent is not as straightforward. Luckily section \S\ref{sec:equiv} gave us some tools to work with equivalences. We saw that we can prove this category univalent by giving an inverse to -$\wideoverbar{\idToIso} \tp (A \equiv B) \to (A \wideoverbar{\approxeq} B)$. -From the original category we have that $\idToIso \tp (A \equiv B) \to (A \cong +$\wideoverbar{\idToIso} \tp (A ≡ B) → (A \wideoverbar{≊} B)$. +From the original category we have that $\idToIso \tp (A ≡ B) → (A \cong B)$ is an isomorphism. Let us denote its inverse with $\isoToId \tp (A -\approxeq B) \to (A \equiv B)$. If we squint we can see what we need is a way to -go between $\wideoverbar{\approxeq}$ and $\approxeq$. +≊ B) → (A ≡ B)$. If we squint we can see what we need is a way to +go between $\wideoverbar{≊}$ and $≊$. -An inhabitant of $A \approxeq B$ is simply an arrow $f \tp \Arrow\ A\ B$ +An inhabitant of $A ≊ B$ is simply an arrow $f \tp \Arrow\ A\ B$ and its inverse $g \tp \Arrow\ B\ A$. In the opposite category $g$ will play the role of the isomorphism and $f$ will be the inverse. Similarly we can -go in the opposite direction. I name these maps $\shufflef \tp (A \approxeq -B) \to (A \wideoverbar{\approxeq} B)$ and $\shufflef^{-1} \tp (A -\wideoverbar{\approxeq} B) \to (A \approxeq B)$ respectively. +go in the opposite direction. I name these maps $\shufflef \tp (A ≊ +B) → (A \wideoverbar{≊} B)$ and $\shufflef^{-1} \tp (A +\wideoverbar{≊} B) → (A ≊ B)$ respectively. As the inverse of $\wideoverbar{\idToIso}$ I will pick $\wideoverbar{\isoToId} -\defeq \isoToId \comp \shufflef$. The proof that they are inverses go as +≜ \isoToId \comp \shufflef$. The proof that they are inverses go as follows: % \begin{align*} @@ -636,21 +636,21 @@ follows: \\ %% ≡⟨ cong (λ \; φ → φ x) (cong (λ \; φ → η ⊙ shuffle ⊙ φ) (funExt lem)) ⟩ \\ % -& \equiv +& ≡ \isoToId \comp \shufflef \comp \inv{\shufflef} \comp \idToIso && \text{lemma} \\ %% ≡⟨⟩ \\ -& \equiv +& ≡ \isoToId \comp \idToIso && \text{$\shufflef$ is an isomorphism} \\ -& \equiv +& ≡ \identity && \text{$\isoToId$ is an isomorphism} \end{align*} % The other direction is analogous. -The lemma used in step 2 of this proof states that $\wideoverbar{idToIso} \equiv +The lemma used in step 2 of this proof states that $\wideoverbar{idToIso} ≡ \inv{\shufflef} \comp \idToIso$. This is a rather straightforward proof since being-an-inverse-of is a proposition, so it suffices to show that their first components are equal, but this holds judgmentally. @@ -659,7 +659,7 @@ This finished the proof that the opposite category is in fact a category. Now, to prove that that opposite-of is an involution we must show: % $$ -\prod_{\bC \tp \Category} \left(\bC^{\var{Op}}\right)^{\var{Op}} \equiv \bC +∏_{\bC \tp \Category} \left(\bC^{\var{Op}}\right)^{\var{Op}} ≡ \bC $$ % As we have seen the laws in $\left(\bC^{\var{Op}}\right)^{\var{Op}}$ get quite @@ -671,7 +671,7 @@ just by giving an equality on the data-part. So, given a category $\bC$ all we must provide is the following proof: % $$ -\var{raw}\ \left(\bC^{\var{Op}}\right)^{\var{Op}} \equiv \var{raw}\ \bC +\var{raw}\ \left(\bC^{\var{Op}}\right)^{\var{Op}} ≡ \var{raw}\ \bC $$ % And these are judgmentally the same. I remind the reader that the left-hand side @@ -681,7 +681,7 @@ is constructed by flipping the arrows, which judgmentally is an involution. The category of sets has as objects, not types, but only those types that are homotopic sets. This is encapsulated in Agda with the following type: % -$$\Set \defeq \sum_{A \tp \MCU} \isSet\ A$$ +$$\Set ≜ ∑_{A \tp \MCU} \isSet\ A$$ % The more straightforward notion of a category where the objects are types is not a valid \mbox{(1-)category}. This stems from the fact that types in cubical @@ -689,15 +689,15 @@ Agda types can have higher homotopic structure. Univalence does not follow immediately from univalence for types: % -$$(A \equiv B) \simeq (A \simeq B)$$ +$$(A ≡ B) ≃ (A ≃ B)$$ % Because here $A, B \tp \Type$ whereas the objects in this category have the type -$\Set$ so we cannot form the type $\var{hA} \simeq \var{hB}$ for objects +$\Set$ so we cannot form the type $\var{hA} ≃ \var{hB}$ for objects $\var{hA}\;\var{hB} \tp \Set$. In stead I show that this category satisfies: % $$ -(\var{hA} \equiv \var{hB}) \simeq (\var{hA} \approxeq \var{hB}) +(\var{hA} ≡ \var{hB}) ≃ (\var{hA} ≊ \var{hB}) $$ % Which, as we saw in section \S\ref{sec:univalence}, is sufficient to show that the @@ -706,18 +706,18 @@ process. For objects $(A, s_A)\; (B, s_B) \tp \Set$ I show the following chain of equivalences: % \begin{align*} -((A, s_A) \equiv (B, s_B)) - & \simeq (A \equiv B) && \ref{eq:equivPropSig} \\ - & \simeq (A \simeq B) && \text{Univalence} \\ - & \simeq ((A, s_A) \approxeq (B, s_B)) && \text{\ref{eq:equivSig} and \ref{eq:equivIso}} +((A, s_A) ≡ (B, s_B)) + & ≃ (A ≡ B) && \ref{eq:equivPropSig} \\ + & ≃ (A ≃ B) && \text{Univalence} \\ + & ≃ ((A, s_A) ≊ (B, s_B)) && \text{\ref{eq:equivSig} and \ref{eq:equivIso}} \end{align*} -And since $\simeq$ is an equivalence relation we can chain these equivalences +And since $≃$ is an equivalence relation we can chain these equivalences together. Step one will be proven with the following lemma: % \begin{align} \label{eq:equivPropSig} -\left(\prod_{a \tp A} \isProp\ (P\ a)\right) \to \prod_{x\;y \tp \sum_{a \tp A} P\ a} (x \equiv y) \simeq (\fst\ x \equiv \fst\ y) +\left(∏_{a \tp A} \isProp\ (P\ a)\right) → ∏_{x\;y \tp ∑_{a \tp A} P\ a} (x ≡ y) ≃ (\fst\ x ≡ \fst\ y) \end{align} % The lemma states that for pairs whose second component are mere propositions @@ -728,30 +728,30 @@ lemma: % \begin{align} \label{eq:equivSig} -\prod_{a \tp A} \left( P\ a \simeq Q\ a \right) \to \sum_{a \tp A} P\ a \simeq \sum_{a \tp A} Q\ a +∏_{a \tp A} \left( P\ a ≃ Q\ a \right) → ∑_{a \tp A} P\ a ≃ ∑_{a \tp A} Q\ a \end{align} % Which says that if two type-families are equivalent at all points, then pairs with identical first components and these families as second components will -also be equivalent. For our purposes $P \defeq \isEquiv\ A\ B$ and $Q \defeq +also be equivalent. For our purposes $P ≜ \isEquiv\ A\ B$ and $Q ≜ \Isomorphism$. So we must finally prove: % \begin{align} \label{eq:equivIso} -\prod_{f \tp A \to B} \left( \isEquiv\ A\ B\ f \simeq \Isomorphism\ f \right) +∏_{f \tp A → B} \left( \isEquiv\ A\ B\ f ≃ \Isomorphism\ f \right) \end{align} -First, lets prove \ref{eq:equivPropSig}: Let $propP \tp \prod_{a \tp A} \isProp\ (P\ a)$ and $x\;y \tp \sum_{a \tp A} P\ a$ be given. Because +First, lets prove \ref{eq:equivPropSig}: Let $propP \tp ∏_{a \tp A} \isProp\ (P\ a)$ and $x\;y \tp ∑_{a \tp A} P\ a$ be given. Because of $\var{fromIsomorphism}$ it suffices to give an isomorphism between -$x \equiv y$ and $\fst\ x \equiv \fst\ y$: +$x ≡ y$ and $\fst\ x ≡ \fst\ y$: % %% FIXME: Too much alignement? \begin{equation*} \begin{aligned} - f & \defeq \congruence\ \fst - && \tp x \equiv y && \to \fst\ x \equiv \fst\ y \\ - g & \defeq \var{lemSig}\ \var{propP}\ x\ y - && \tp \fst\ x \equiv \fst\ y && \to x \equiv y + f & ≜ \congruence\ \fst + && \tp x ≡ y && → \fst\ x ≡ \fst\ y \\ + g & ≜ \var{lemSig}\ \var{propP}\ x\ y + && \tp \fst\ x ≡ \fst\ y && → x ≡ y \end{aligned} \end{equation*} % @@ -761,9 +761,9 @@ suffices to give a path between its first components to construct an equality of the two pairs: % \begin{align*} -\var{lemSig} \tp \left( \prod_{x \tp A} \isProp\ (B\ x) \right) \to -\prod_{u\; v \tp \sum_{a \tp A} B\ a} - \left( \fst\ u \equiv \fst\ v \right) \to u \equiv v +\var{lemSig} \tp \left( ∏_{x \tp A} \isProp\ (B\ x) \right) → +∏_{u\; v \tp ∑_{a \tp A} B\ a} + \left( \fst\ u ≡ \fst\ v \right) → u ≡ v \end{align*} % The proof that these are indeed inverses has been omitted. The details @@ -772,41 +772,41 @@ can be found in the module: \sourcelink{Cat.Categories.Sets} \end{center} -Now to prove \ref{eq:equivSig}: Let $e \tp \prod_{a \tp A} \left( P\ a -\simeq Q\ a \right)$ be given. To prove the equivalence, it suffices -to give an isomorphism between $\sum_{a \tp A} P\ a$ and $\sum_{a \tp +Now to prove \ref{eq:equivSig}: Let $e \tp ∏_{a \tp A} \left( P\ a +≃ Q\ a \right)$ be given. To prove the equivalence, it suffices +to give an isomorphism between $∑_{a \tp A} P\ a$ and $∑_{a \tp A} Q\ a$, but since they have identical first components it suffices to give an isomorphism between $P\ a$ and $Q\ a$ for all $a \tp A$. This is exactly what we can get from the equivalence $e$.\QED -Lastly we prove \ref{eq:equivIso}. Let $f \tp A \to B$ be given. For the maps we +Lastly we prove \ref{eq:equivIso}. Let $f \tp A → B$ be given. For the maps we choose: % \begin{align*} \var{toIso} - & \tp \isEquiv\ f \to \Isomorphism\ f \\ + & \tp \isEquiv\ f → \Isomorphism\ f \\ \var{fromIso} - & \tp \Isomorphism\ f \to \isEquiv\ f + & \tp \Isomorphism\ f → \isEquiv\ f \end{align*} % As mentioned in section \S\ref{sec:equiv}. These maps are not in general inverses of each other. In stead, we will use the fact that $A$ and $B$ are sets. The first thing we must prove is: % \begin{align*} - \var{fromIso} \comp \var{toIso} \equiv \identity_{\isEquiv\ f} + \var{fromIso} \comp \var{toIso} ≡ \identity_{\isEquiv\ f} \end{align*} % For this we can use the fact that being-an-equivalence is a mere proposition. For the other direction: % \begin{align*} - \var{toIso} \comp \var{fromIso} \equiv \identity_{\Isomorphism\ f} + \var{toIso} \comp \var{fromIso} ≡ \identity_{\Isomorphism\ f} \end{align*} % We will show that $\Isomorphism\ f$ is also a mere proposition. To this end, let $X\;Y \tp \Isomorphism\ f$ be given. Name the maps $x\;y \tp B -\to A$ respectively. Now, the proof that $X$ and $Y$ are the same is a pair of -paths: $p \tp x \equiv y$ and $\Path\ (\lambda\; i \to +→ A$ respectively. Now, the proof that $X$ and $Y$ are the same is a pair of +paths: $p \tp x ≡ y$ and $\Path\ (\lambda\; i → \var{AreInverses}\ f\ (p\ i))\ \mathcal{X}\ \mathcal{Y}$ where $\mathcal{X}$ and $\mathcal{Y}$ denotes the witnesses that $x$ (respectively $y$) is an inverse to $f$. The path $p$ is inhabited by: @@ -814,10 +814,10 @@ inverse to $f$. The path $p$ is inhabited by: \begin{align*} x & = x \comp \identity \\ - & \equiv x \comp (f \comp y) + & ≡ x \comp (f \comp y) && \text{$y$ is an inverse to $f$} \\ - & \equiv (x \comp f) \comp y \\ - & \equiv \identity \comp y + & ≡ (x \comp f) \comp y \\ + & ≡ \identity \comp y && \text{$x$ is an inverse to $f$} \\ & = y \end{align*} @@ -827,7 +827,7 @@ proposition and then use $\lemPropF$. So we prove the generalization: % \begin{align} \label{eq:propAreInversesGen} -\prod_{g \tp B \to A} \isProp\ (\var{AreInverses}\ f\ g) +∏_{g \tp B → A} \isProp\ (\var{AreInverses}\ f\ g) \end{align} % But $\var{AreInverses}\ f\ g$ is a pair of equations on arrows, so we use @@ -854,7 +854,7 @@ demonstrated. The goal in this section is to show that products are propositions: % $$ -\prod_{\bC \tp \Category} \prod_{A\;B \tp \Object} \isProp\ (\var{Product}\ \bC\ A\ B) +∏_{\bC \tp \Category} ∏_{A\;B \tp \Object} \isProp\ (\var{Product}\ \bC\ A\ B) $$ % Where $\var{Product}\ \bC\ A\ B$ denotes the type of products of objects $A$ @@ -867,7 +867,7 @@ we recall the definition of products. \subsection{Definition of products} Given a category $\bC$ and two objects $A$ and $B$ in $\bC$ we define the product (object) of $A$ and $B$ to be an object $A \x B$ in $\bC$ and two arrows -$\pi_1 \tp A \x B \to A$ and $\pi_2 \tp A \x B \to B$ called the projections of +$\pi_1 \tp A \x B → A$ and $\pi_2 \tp A \x B → B$ called the projections of the product. The projections must satisfy the following property: For all $X \tp Object$, $f \tp \Arrow\ X\ A$ and $g \tp \Arrow\ X\ B$ we have @@ -875,9 +875,9 @@ that there exists a unique arrow $\pi \tp \Arrow\ X\ (A \x B)$ satisfying % \begin{align} \label{eq:umpProduct} -%% \prod_{X \tp Object} \prod_{f \tp \Arrow\ X\ A} \prod_{g \tp \Arrow\ X\ B}\\ +%% ∏_{X \tp Object} ∏_{f \tp \Arrow\ X\ A} ∏_{g \tp \Arrow\ X\ B}\\ %% \uexists_{f \x g \tp \Arrow\ X\ (A \x B)} -\pi_1 \lll \pi \equiv f \x \pi_2 \lll \pi \equiv g +\pi_1 \lll \pi ≡ f \x \pi_2 \lll \pi ≡ g \end{align} % $\pi$ is called the product (arrow) of $f$ and $g$. @@ -900,8 +900,8 @@ category will consist of an arrow from the underlying category $\pairf \tp % \begin{align} \label{eq:pairArrowLaw} -b_0 \lll f \equiv a_0 \x -b_1 \lll f \equiv a_1 +b_0 \lll f ≡ a_0 \x +b_1 \lll f ≡ a_1 \end{align} The identity morphism is the identity morphism from the underlying category. @@ -914,13 +914,13 @@ choose $g \lll f$ and we must now verify that it satisfies % \begin{align*} c_0 \lll (f \lll g) - & \equiv + & ≡ (c_0 \lll f) \lll g && \text{Associativity} \\ - & \equiv + & ≡ b_0 \lll g && \text{$f$ satisfies \ref{eq:pairArrowLaw}} \\ - & \equiv + & ≡ a_0 && \text{$g$ satisfies \ref{eq:pairArrowLaw}} \\ \end{align*} @@ -932,7 +932,7 @@ arrows form a set. For instance, to prove associativity we must prove that \begin{align} \label{eq:productAssoc} \overline{h} \lll (\overline{g} \lll \overline{f}) -\equiv +≡ (\overline{h} \lll \overline{g}) \lll \overline{f} \end{align} % @@ -947,7 +947,7 @@ The proof obligations is consists of two things. The first one is: \begin{align} \label{eq:productAssocUnderlying} h \lll (g \lll f) -\equiv +≡ (h \lll g) \lll f \end{align} % @@ -976,7 +976,7 @@ stead we generalize \ref{eq:productPath} to: % \begin{align} \label{eq:productEqPrinc} -\prod_{f \tp \Arrow\ X\ Y} \isProp\ \left( y_{\pairA} \lll f ≡ x_{\pairA} × y_{\pairB} \lll f ≡ x_{\pairB} \right) +∏_{f \tp \Arrow\ X\ Y} \isProp\ \left( y_{\pairA} \lll f ≡ x_{\pairA} × y_{\pairB} \lll f ≡ x_{\pairB} \right) \end{align} % For all objects $X , x_{\pairA} , x_{\pairB}$ and $Y , y_{\pairA} , y_{\pairB}$, @@ -986,7 +986,7 @@ in this category that says that to prove two arrows $f, f_0, f_1$ and $g, g_0, g_1$ equal it suffices to give a proof that $f$ and $g$ are equal. %% % %% $$ -%% \prod_{(f, f_0, f_1)\; (g,g_0,g_1) \tp \Arrow\ X\ Y} f \equiv g \to (f, f_0, f_1) \equiv (g,g_0,g_1) +%% ∏_{(f, f_0, f_1)\; (g,g_0,g_1) \tp \Arrow\ X\ Y} f ≡ g \to (f, f_0, f_1) ≡ (g,g_0,g_1) %% $$ %% % And thus we have proven \ref{eq:productAssoc} simply with @@ -1007,7 +1007,7 @@ $$ Which holds. And % $$ -\prod_{f \tp \Arrow\ X\ Y} +∏_{f \tp \Arrow\ X\ Y} \isSet\ \left( y_{\pairA} \lll f ≡ x_{\pairA} × y_{\pairB} \lll f ≡ x_{\pairB} \right) @@ -1024,7 +1024,7 @@ That is, for any two objects $\mathcal{X} = (X, x_{\mathcal{A}} , x_{\mathcal{B} and $\mathcal{Y} = Y, y_{\mathcal{A}}, y_{\mathcal{B}}$ I will show: % \begin{align} -(\mathcal{X} \equiv \mathcal{Y}) \cong (\mathcal{X} \approxeq \mathcal{Y}) +(\mathcal{X} ≡ \mathcal{Y}) \cong (\mathcal{X} ≊ \mathcal{Y}) \end{align} I do this by showing that the following sequence of types are isomorphic. @@ -1041,7 +1041,7 @@ The next types will be the triple: \begin{align} \label{eq:univ-1} \begin{split} -p \tp & X \equiv Y \\ +p \tp & X ≡ Y \\ & \Path\ (λ \; i → \Arrow\ (p\ i)\ \mathcal{A})\ x_{\mathcal{A}}\ y_{\mathcal{A}} \\ & \Path\ (λ \; i → \Arrow\ (p\ i)\ \mathcal{B})\ x_{\mathcal{B}}\ y_{\mathcal{B}} \end{split} @@ -1054,13 +1054,13 @@ isomorphism, and create a path from this: \begin{align} \label{eq:univ-2} \begin{split} -\var{iso} \tp & X \approxeq Y \\ +\var{iso} \tp & X ≊ Y \\ & \Path\ (λ \; i → \Arrow\ (\widetilde{p}\ i)\ \mathcal{A})\ x_{\mathcal{A}}\ y_{\mathcal{A}} \\ & \Path\ (λ \; i → \Arrow\ (\widetilde{p}\ i)\ \mathcal{B})\ x_{\mathcal{B}}\ y_{\mathcal{B}} \end{split} \end{align} % -Where $\widetilde{p} \defeq \isoToId\ \var{iso} \tp X \equiv Y$. +Where $\widetilde{p} ≜ \isoToId\ \var{iso} \tp X ≡ Y$. Finally we have the type: % @@ -1085,15 +1085,15 @@ This proof of this has been omitted but can be found in the module: will show two corollaries of \ref{eq:coeCod}: For an isomorphism $(\iota, \inv{\iota}, \var{inv}) \tp A \cong B$, arrows $f \tp \Arrow\ A\ X$, $g \tp \Arrow\ B\ X$ and a heterogeneous path between them, $q \tp \Path\ (\lambda\; i -\to p_{\var{dom}}\ i)\ f\ g$, where $p_{\var{dom}} \tp \Arrow\ A\ X \equiv +→ p_{\var{dom}}\ i)\ f\ g$, where $p_{\var{dom}} \tp \Arrow\ A\ X ≡ \Arrow\ B\ X$ is a path induced by $\var{iso}$, we have the following two results % \begin{align} \label{eq:domain-twist-0} -f & \equiv g \lll \iota \\ +f & ≡ g \lll \iota \\ \label{eq:domain-twist-1} -g & \equiv f \lll \inv{\iota} +g & ≡ f \lll \inv{\iota} \end{align} % The proof is omitted but can be found in the module: @@ -1105,14 +1105,14 @@ Now we can prove the equivalence in the following way: Given $(f, \inv{f}, \var{inv}_f) \tp X \cong Y$ and two heterogeneous paths % \begin{align*} -p_{\mathcal{A}} & \tp \Path\ (\lambda\; i \to p_{\var{dom}}\ i)\ x_{\mathcal{A}}\ y_{\mathcal{A}}\\ +p_{\mathcal{A}} & \tp \Path\ (\lambda\; i → p_{\var{dom}}\ i)\ x_{\mathcal{A}}\ y_{\mathcal{A}}\\ % -q_{\mathcal{B}} & \tp \Path\ (\lambda\; i \to p_{\var{dom}}\ i)\ x_{\mathcal{B}}\ y_{\mathcal{B}} +q_{\mathcal{B}} & \tp \Path\ (\lambda\; i → p_{\var{dom}}\ i)\ x_{\mathcal{B}}\ y_{\mathcal{B}} \end{align*} % all as in \ref{eq:univ-2}. I use $p_{\var{dom}}$ here again to mean the path induced by the isomorphism $f, \inv{f}$. I must now construct an isomorphism -$(X, x_{\mathcal{A}}, x_{\mathcal{B}}) \approxeq (Y, y_{\mathcal{A}}, y_{\mathcal{B}})$ +$(X, x_{\mathcal{A}}, x_{\mathcal{B}}) ≊ (Y, y_{\mathcal{A}}, y_{\mathcal{B}})$ as in \ref{eq:univ-3}. That is, an isomorphism in the present category. I remind the reader that such a gadget is a triple. The first component shall be: % @@ -1145,7 +1145,7 @@ For the other direction we are given the isomorphism: $$ (f, \inv{f}, \var{inv}_f, \var{inv}_{\inv{f}}) \tp -(X, x_{\mathcal{A}}, x_{\mathcal{B}}) \approxeq (Y, y_{\mathcal{A}}, y_{\mathcal{B}}) +(X, x_{\mathcal{A}}, x_{\mathcal{B}}) ≊ (Y, y_{\mathcal{A}}, y_{\mathcal{B}}) $$ % Projecting out the first component gives us the isomorphism @@ -1155,16 +1155,16 @@ $$ , \congruence\ \fst\ \var{inv}_f , \congruence\ \fst\ \var{inv}_{\inv{f}} ) -\tp X \approxeq Y +\tp X ≊ Y $$ % This gives rise to the following paths: % \begin{align} \begin{split} -\widetilde{p} & \tp X \equiv Y \\ -\widetilde{p}_{\mathcal{A}} & \tp \Arrow\ X\ \mathcal{A} \equiv \Arrow\ Y\ \mathcal{A} \\ -\widetilde{p}_{\mathcal{B}} & \tp \Arrow\ X\ \mathcal{B} \equiv \Arrow\ Y\ \mathcal{B} +\widetilde{p} & \tp X ≡ Y \\ +\widetilde{p}_{\mathcal{A}} & \tp \Arrow\ X\ \mathcal{A} ≡ \Arrow\ Y\ \mathcal{A} \\ +\widetilde{p}_{\mathcal{B}} & \tp \Arrow\ X\ \mathcal{B} ≡ \Arrow\ Y\ \mathcal{B} \end{split} \end{align} % @@ -1181,7 +1181,7 @@ It then remains to construct the two paths: This is achieved with the following lemma: % \begin{align} -\prod_{a \tp A} \prod_{b \tp B} \prod_{q \tp A \equiv B} \var{coe}\ q\ a ≡ b → +∏_{a \tp A} ∏_{b \tp B} ∏_{q \tp A ≡ B} \var{coe}\ q\ a ≡ b → \Path\ (λ \; i → q\ i)\ a\ b \end{align} % @@ -1263,15 +1263,15 @@ is the proof that $f$ satisfies \ref{eq:pairCondRev}). The proof will be a pair of proofs: % \begin{alignat}{3} - p \tp & \Path\ (\lambda\; i \to \Arrow\ X\ Y)\quad + p \tp & \Path\ (\lambda\; i → \Arrow\ X\ Y)\quad && f\quad && y_𝒜 \x y_ℬ \\ - & \Path\ (\lambda\; i \to \Phi\ (p\ i))\quad + & \Path\ (\lambda\; i → \Phi\ (p\ i))\quad && \phi_f\quad && \phi_{y_𝒜 \x y_ℬ} \end{alignat} % Here $\Phi$ is given as: $$ -\prod_{f \tp \Arrow\ Y\ X} +∏_{f \tp \Arrow\ Y\ X} ( x_𝒜 \lll f ≡ y_𝒜 ) × ( x_ℬ \lll f ≡ y_ℬ ) @@ -1282,7 +1282,7 @@ again use the same trick we did in \ref{eq:propAreInversesGen} and prove this more general result: % $$ -\prod_{f \tp \Arrow\ Y\ X} \isProp\ ( +∏_{f \tp \Arrow\ Y\ X} \isProp\ ( ( x_𝒜 \lll f ≡ y_𝒜 ) × ( x_ℬ \lll f ≡ y_ℬ ) @@ -1298,7 +1298,7 @@ preserve homotopic levels along with \ref{eq:termProp} we get our final result. That in any category: % \begin{align} -\prod_{A, B \tp \Object} \isProp\ (\var{Product}\ \bC\ A\ B) +∏_{A, B \tp \Object} \isProp\ (\var{Product}\ \bC\ A\ B) \end{align} % \section{Functors and natural transformations} @@ -1331,7 +1331,7 @@ Given two functors between categories $\bC$ and $\bD$. Name them $\FunF$ and $\FunG$. A natural transformation is a family of arrows: % \begin{align*} -\prod_{C \tp ℂ.\Object} \bD.\Arrow\ (\omapF\ C)\ (\omapG\ C) +∏_{C \tp ℂ.\Object} \bD.\Arrow\ (\omapF\ C)\ (\omapG\ C) \end{align*} % This family of arrows can be seen as the data. If $\theta$ is a @@ -1340,7 +1340,7 @@ $\theta$) at $C$. The laws of this family of morphism is the naturality condition: % \begin{align*} -\prod_{f \tp ℂ.\Arrow\ A\ B} +∏_{f \tp ℂ.\Arrow\ A\ B} (θ\ B) \dlll (\FunF.\fmap\ f) ≡ (\FunG.\fmap\ f) \dlll (θ\ A) \end{align*} % @@ -1409,9 +1409,9 @@ The Kleisli-formulation consists of the following data: \begin{split} \label{eq:monad-kleisli-data} \omapR & \tp \Object → \Object \\ -\pure & \tp % \prod_{X \tp Object} +\pure & \tp % ∏_{X \tp Object} \Arrow\ X\ (\omapR\ X) \\ - \bind & \tp % \prod_{X\;Y \tp Object} → \Arrow\ X\ (\omapR\ Y) + \bind & \tp % ∏_{X\;Y \tp Object} → \Arrow\ X\ (\omapR\ Y) \Arrow\ (\omapR\ X)\ (\omapR\ Y) \end{split} \end{align} @@ -1420,9 +1420,9 @@ The objects $X$ and $Y$ are implicitly universally quantified. With this data we % \begin{align*} \fish & \tp \Arrow\ A\ (\omapR\ B) - \to \Arrow\ B\ (\omapR\ C) - \to \Arrow\ A\ (\omapR\ C) \\ -f \fish g & \defeq f \rrr (\bind\ g) + → \Arrow\ B\ (\omapR\ C) + → \Arrow\ A\ (\omapR\ C) \\ +f \fish g & ≜ f \rrr (\bind\ g) \end{align*} % It is interesting to note here that this formulation does not talk about natural @@ -1461,13 +1461,13 @@ In the monoidal formulation we can define $\bind$: \newcommand\pureX{\wideoverbar{\pure}}% \newcommand\fmapX{\wideoverbar{\fmap}}% \begin{align} -\bind\ f \defeq \join \lll \fmap\ f +\bind\ f ≜ \join \lll \fmap\ f \end{align} % And likewise in the Kleisli formulation we can define $\join$: % \begin{align} -\join \defeq \bind\ \identity +\join ≜ \bind\ \identity \end{align} % It now remains to show that this construction indeed gives rise to a @@ -1483,9 +1483,9 @@ formulation we pick: % \begin{align} \begin{split} - \omapR & \defeq \omapR \\ - \pure & \defeq \pure \\ - \bind\ f & \defeq \join \lll \fmap\ f + \omapR & ≜ \omapR \\ + \pure & ≜ \pure \\ + \bind\ f & ≜ \join \lll \fmap\ f \end{split} \end{align} % @@ -1549,9 +1549,9 @@ the monoidal formulation we pick: % \begin{align} \begin{split} - \EndoR & \defeq (\omapR, \bind\ (\pure \lll f)) \\ - \pure & \defeq \pure \\ - \join & \defeq \bind\ \identity + \EndoR & ≜ (\omapR, \bind\ (\pure \lll f)) \\ + \pure & ≜ \pure \\ + \join & ≜ \bind\ \identity \end{split} \end{align} % @@ -1570,23 +1570,23 @@ that the two mappings sketched above are indeed inverses of each other. To recap, these maps are: % \begin{align*} - \toKleisli & \tp \var{Kleisli} \to \var{Monoidal} \\ - \toKleisli & \defeq \lambda\ (\omapR, \pure, \bind) - \to (\EndoR, \pure, \bind\ \identity) + \toKleisli & \tp \var{Kleisli} → \var{Monoidal} \\ + \toKleisli & ≜ \lambda\ (\omapR, \pure, \bind) + → (\EndoR, \pure, \bind\ \identity) \end{align*} % -Where $\EndoR \defeq (\omapR, \bind\ (\pure \lll f))$. The proof that +Where $\EndoR ≜ (\omapR, \bind\ (\pure \lll f))$. The proof that this is indeed a functor is left implicit as well as the monad laws. Likewise the proof that $\pure$ and $\bind\ \identity$ are natural transformations are left implicit. The inverse map will be: % \begin{align*} - \toMonoidal & \tp \var{Monoidal} \to \var{Kleisli} \\ - \toMonoidal & \defeq \lambda\ (\EndoR, \pureNT, \joinNT) - \to (\omapR, \pure, \bind) + \toMonoidal & \tp \var{Monoidal} → \var{Kleisli} \\ + \toMonoidal & ≜ \lambda\ (\EndoR, \pureNT, \joinNT) + → (\omapR, \pure, \bind) \end{align*} % -Where $\bind\ f \defeq \join \lll \fmap\ f$. Again the monad laws are +Where $\bind\ f ≜ \join \lll \fmap\ f$. Again the monad laws are left implicit. Now we must show: % \begin{align} From 37a675a84f86c2258e8ede1875136d213f71ad45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frederik=20Hangh=C3=B8j=20Iversen?= Date: Tue, 29 May 2018 15:09:38 +0200 Subject: [PATCH 30/33] Final touch-up on report and acknowledgments --- doc/acknowledgement.tex | 1 + doc/conclusion.tex | 68 +-- doc/discussion.tex | 149 +++-- doc/implementation.tex | 1169 ++++++++++++++++++++------------------- doc/introduction.tex | 4 +- 5 files changed, 715 insertions(+), 676 deletions(-) create mode 100644 doc/acknowledgement.tex diff --git a/doc/acknowledgement.tex b/doc/acknowledgement.tex new file mode 100644 index 0000000..5cd6cc3 --- /dev/null +++ b/doc/acknowledgement.tex @@ -0,0 +1 @@ +\chapter*{Acknowledgements} diff --git a/doc/conclusion.tex b/doc/conclusion.tex index c4d0d10..67f4075 100644 --- a/doc/conclusion.tex +++ b/doc/conclusion.tex @@ -1,53 +1,53 @@ \chapter{Conclusion} This thesis highlighted some issues with the standard inductive -definition of propositional equality used in Agda. Functional +definition of propositional equality used in Agda. Functional extensionality and univalence are examples of two propositions not -admissible in Intensional Type Theory (ITT). This has a big impact on -what is provable and the reusability of proofs. This issue is overcome -with an extension to Agda's type system called Cubical Agda. With -Cubical Agda both functional extensionality and univalence are -admissible. Cubical Agda is more expressive, but there are certain -issues that arise that are not present in standard Agda. For one thing -Agda enjoys Uniqueness of Identity Proofs (UIP) though a flag exists -to turn this off, which is the case in Cubical Agda. In stead -there exists a hierarchy of types with increasing \nomen{homotopical +admissible in Intensional Type Theory (ITT). This has a big impact on +what is provable and the reusability of proofs. This issue is +overcome with an extension to Agda's type system called Cubical Agda. +With Cubical Agda both functional extensionality and univalence are +admissible. Cubical Agda is more expressive, but there are certain +issues that arise that are not present in standard Agda. For one +thing Agda enjoys Uniqueness of Identity Proofs (UIP) though a flag +exists to turn this off. This feature is not present in Cubical Agda. +Rather than having unique identity proofs cubical Agda gives rise to a +hierarchy of types with increasing \nomen{homotopical structure}{homotopy levels}. It turns out to be useful to built the formalization with this hierarchy in mind as it can simplify proofs -considerably. Another issue one must overcome in Cubical Agda is when -a type has a field whose type depends on a previous field. In this -case paths between such types will be heterogeneous paths. This -problem is related to Cubical Agda not having the K-rule. In practice -it turns out to be considerably more difficult to work heterogeneous -paths than with homogeneous paths. The thesis demonstrated some -techniques to overcome these difficulties, such as based -path-induction. +considerably. Another issue one must overcome in Cubical Agda is when +a type has a field whose type depends on a previous field. In this +case paths between such types will be heterogeneous paths. In +practice it turns out to be considerably more difficult to work with +heterogeneous paths than with homogeneous paths. The thesis +demonstrated the application of some techniques to overcome these +difficulties, such as based path induction. -This thesis formalized some of the core concepts from category theory +This thesis formalizes some of the core concepts from category theory including; categories, functors, products, exponentials, Cartesian closed categories, natural transformations, the yoneda embedding, -monads and more. Category theory is an interesting case-study for the -application of Cubical Agda for two reasons in particular: Because +monads and more. Category theory is an interesting case study for the +application of cubical Agda for two reasons in particular: Because category theory is the study of abstract algebra of functions, meaning that functional extensionality is particularly relevant. Another reason is that in category theory it is commonplace to identify -isomorphic structures and univalence allows for making this notion -precise. This thesis also demonstrated another technique that is +isomorphic structures. Univalence allows for making this notion +precise. This thesis also demonstrated another technique that is common in category theory; namely to define categories to prove properties of other structures. Specifically a category was defined to demonstrate that any two product objects in a category are -isomorphic. Furthermore the thesis showed two formulations of monads +isomorphic. Furthermore the thesis showed two formulations of monads and proved that they indeed are equivalent: Namely monads in the -monoidal- and Kleisli- form. The monoidal formulation is more typical +monoidal- and Kleisli- form. The monoidal formulation is more typical to category theoretic formulations and the Kleisli formulation will be -more familiar to functional programmers. It would have been very -difficult to make a similar proof with setoids. In the formulation we -also saw how paths can be used to extract functions. A path between -two types induce an isomorphism between the two types. This -e.g. permits developers to write a monad instance for a given type -using the Kleisli formulation. By transporting along the path between -the monoidal- and Kleisli- formulation one can reuse all the -operations and results shown for monoidal- monads in the context of -kleisli monads. +more familiar to functional programmers. It would have been very +difficult to make a similar proof with setoids and the proof would be +very difficult to read. In the formulation we also saw how paths can +be used to extract functions. A path between two types induce an +isomorphism between the two types. This e.g.\ permits developers to +write a monad instance for a given type using the Kleisli formulation. +By transporting along the path between the monoidal- and Kleisli- +formulation one can reuse all the operations and results shown for +monoidal- monads in the context of kleisli monads. %% %% problem with inductive type %% overcome with cubical diff --git a/doc/discussion.tex b/doc/discussion.tex index 56177ef..6d87beb 100644 --- a/doc/discussion.tex +++ b/doc/discussion.tex @@ -1,113 +1,113 @@ \chapter{Perspectives} \section{Discussion} In the previous chapter the practical aspects of proving things in -Cubical Agda were highlighted. I also demonstrated the usefulness of -separating ``laws'' from ``data''. One of the reasons for this is that -dependencies within types can lead to very complicated goals. One +Cubical Agda were highlighted. I also demonstrated the usefulness of +separating ``laws'' from ``data''. One of the reasons for this is that +dependencies within types can lead to very complicated goals. One technique for alleviating this was to prove that certain types are mere propositions. \subsection{Computational properties} The new contribution of cubical Agda is that it has a constructive proof of functional extensionality\index{functional extensionality} -and univalence\index{univalence}. This means that in particular that -the type checker can reduce terms defined with these theorems. So one +and univalence\index{univalence}. This means that in particular that +the type checker can reduce terms defined with these theorems. So one interesting result of this development is how much this influenced the -development. In particular having a functional extensionality that +development. In particular having a functional extensionality that ``computes'' should simplify some proofs. -I have tested this theory by using a feature of Agda where one can -mark certain bindings as being \emph{abstract}. This means that the -type-checker will not try to reduce that term further when -type-checking is performed. I tried making univalence and functional -extensionality abstract. It turns out that the conversion behaviour of -univalence is not used anywhere. For functional extensionality there -are two places in the whole solution where the reduction behaviour is -used to simplify some proofs. This is in showing that the maps between -the two formulations of monads are inverses. See the notes in this +I have tested this by using a feature of Agda where one can mark +certain bindings as being \emph{abstract}. This means that the +type-checker will not try to reduce that term further during type +checking. I tried making univalence and functional extensionality +abstract. It turns out that the conversion behaviour of univalence is +not used anywhere. For functional extensionality there are two places +in the whole solution where the reduction behaviour is used to +simplify some proofs. This is in showing that the maps between the +two formulations of monads are inverses. See the notes in this module: % \begin{center} \sourcelink{Cat.Category.Monad.Voevodsky} \end{center} % -I've also put this in a source listing in \ref{app:abstract-funext}. I -will not reproduce it in full here as the type is quite involved. The -method used to find in what places the computational behaviour of -these proofs are needed has the caveat of only working for places that -directly or transitively uses these two proofs. Fortunately though the -code is structured in such a way that this should be the case. -Nonetheless it is quite surprising that this computational behaviours -is not used more widely in the formalization. -Barring this, however, the computational behaviour of paths can still -be useful. E.g. if a programmer want's to reuse functions that operate -on a monoidal monads to work with a monad in the Kleisli form that -this programmer has specified. To make this idea concrete, say we are +I will not reproduce it in full here as the type is quite involved. In +stead I have put this in a source listing in \ref{app:abstract-funext}. +The method used to find in what places the computational behaviour of +these proofs are needed has the caveat of only working for places that +directly or transitively uses these two proofs. Fortunately though +the code is structured in such a way that this is the case. So in +conclusion the way I have structured these proofs means that the +computational behaviour of functional extensionality and univalence +has not been so relevant. + +Barring this the computational behaviour of paths can still be useful. +E.g.\ if a programmer wants to reuse functions that operate on a +monoidal monads to work with a monad in the Kleisli form that the +programmer has specified. To make this idea concrete, say we are given some function $f \tp \Kleisli \to T$ having a path between $p \tp \Monoidal \equiv \Kleisli$ induces a map $\coe\ p \tp \Monoidal -\to \Kleisli$. We can compose $f$ with this map to get $f \comp -\coe\ p \tp \Monoidal \to T$. Of course, since that map was +\to \Kleisli$. We can compose $f$ with this map to get $f \comp +\coe\ p \tp \Monoidal \to T$. Of course, since that map was constructed with an isomorphism these maps already exist and could be -used directly. So this is arguably only interesting when one wants to -prove properties of such functions. +used directly. So this is arguably only interesting when one also +wants to prove properties of applying such functions. \subsection{Reusability of proofs} The previous example illustrate how univalence unifies two otherwise disparate areas: The category-theoretic study of monads; and monads as -in functional programming. Univalence thus allows one to reuse proofs. +in functional programming. Univalence thus allows one to reuse proofs. You could say that univalence gives the developer two proofs for the -price of one. As an illustration of this I proved that monads are -groupoids. I initially proved this for the Kleisli +price of one. As an illustration of this I proved that monads are +groupoids. I initially proved this for the Kleisli formulation\footnote{Actually doing this directly turned out to be tricky as well, so I defined an equivalent formulation which was not - formulated with a record, but purely with $\sum$-types.}. Since the + formulated with a record, but purely with $\sum$-types.}. Since the two formulations are equal under univalence, substitution directly -gives us that this also holds for the monoidal formulation. This of +gives us that this also holds for the monoidal formulation. This of course generalizes to any family $P \tp 𝒰 → 𝒰$ where $P$ is inhabited at either formulation (i.e.\ either $P\ \Monoidal$ or $P\ \Kleisli$ holds). -The introduction (section \S\ref{sec:context}) mentioned an often -employed-technique for enabling extensional equalities is to use the -setoid-interpretation. Nowhere in this formalization has this been -necessary, $\Path$ has been used globally in the project as -propositional equality. One interesting place where this becomes -apparent is in interfacing with the Agda standard library. Multiple -definitions in the Agda standard library have been designed with the -setoid-interpretation in mind. E.g. the notion of ``unique -existential'' is indexed by a relation that should play the role of -propositional equality. Likewise for equivalence relations, they are -indexed, not only by the actual equivalence relation, but also by -another relation that serve as propositional equality. +The introduction (section \S\ref{sec:context}) mentioned that a +typical way of getting access to functional extensionality is to work +with setoids. Nowhere in this formalization has this been necessary, +$\Path$ has been used globally in the project for propositional +equality. One interesting place where this becomes apparent is in +interfacing with the Agda standard library. Multiple definitions in +the Agda standard library have been designed with the +setoid-interpretation in mind. E.g.\ the notion of \emph{unique + existential} is indexed by a relation that should play the role of +propositional equality. Equivalence relations are likewise indexed, +not only by the actual equivalence relation but also by another +relation that serve as propositional equality. %% Unfortunately we cannot use the definition of equivalences found in -%% the standard library to do equational reasoning directly. The +%% the standard library to do equational reasoning directly. The %% reason for this is that the equivalence relation defined there must %% be a homogenous relation, but paths are heterogeneous relations. In the formalization at present a significant amount of energy has been put towards proving things that would not have been needed in -classical Agda. The proofs that some given type is a proposition were +classical Agda. The proofs that some given type is a proposition were provided as a strategy to simplify some otherwise very complicated -proofs (e.g. \ref{eq:proof-prop-IsPreCategory} -and \ref{eq:productPath}). Often these proofs would not be this -complicated. If the J-rule holds definitionally the proof-assistant -can help simplify these goals considerably. The lack of the J-rule has +proofs (e.g.\ \ref{eq:proof-prop-IsPreCategory} +and \ref{eq:productPath}). Often these proofs would not be this +complicated. If the J-rule holds definitionally the proof-assistant +can help simplify these goals considerably. The lack of the J-rule has a significant impact on the complexity of these kinds of proofs. -\TODO{Universe levels.} - \subsection{Motifs} An oft-used technique in this development is using based path -induction to prove certain properties. One particular challenge that +induction to prove certain properties. One particular challenge that arises when doing so is that Agda is not able to automatically infer -the family that one wants to do induction over. For instance in the +the family that one wants to do induction over. For instance in the proof $\var{sym}\ (\var{sym}\ p) ≡ p$ from \ref{eq:sym-invol} the family that we chose to do induction over was $D\ b'\ p' \defeq -\var{sym}\ (\var{sym}\ p') ≡ p'$. However, if one interactively tries +\var{sym}\ (\var{sym}\ p') ≡ p'$. However, if one interactively tries to give this hole, all the information that Agda can provide is that -one must provide an element of $𝒰$. Agda could be more helpful in this -context, perhaps even infer this family in some situations. In this +one must provide an element of $𝒰$. Agda could be more helpful in this +context, perhaps even infer this family in some situations. In this very simple example this is of course not a big problem, but there are examples in the source code where this gets more involved. @@ -115,26 +115,25 @@ examples in the source code where this gets more involved. \subsection{Compiling Cubical Agda} \label{sec:compiling-cubical-agda} Compilation of program written in Cubical Agda is currently not -supported. One issue here is that the backends does not provide an +supported. One issue here is that the backends does not provide an implementation for the cubical primitives (such as the path-type). This means that even though the path-type gives us a computational interpretation of functional extensionality, univalence, transport, etc., we do not have a way of actually using this to compile our -programs that use these primitives. It would be interesting to see -practical applications of this. The path between monads that this -library exposes could provide one particularly interesting case-study. - -\subsection{Higher inductive types} -This library has not explored the usefulness of higher inductive types -in the context of Category Theory. - -\subsection{Initiality conjecture} -A fellow student here at Chalmers, Andreas Källberg, is currently -working on proving the initiality conjecture\TODO{Citation}. He will -be using this library to do so. +programs that use these primitives. It would be interesting to see +practical applications of this. \subsection{Proving laws of programs} Another interesting thing would be to use the Kleisli formulation of -monads to prove properties of functional programs. The existence of +monads to prove properties of functional programs. The existence of univalence will make it possible to re-use proofs stated in terms of the monoidal formulation in this setting. + +%% \subsection{Higher inductive types} +%% This library has not explored the usefulness of higher inductive types +%% in the context of Category Theory. + +\subsection{Initiality conjecture} +A fellow student at Chalmers, Andreas Källberg, is currently working +on proving the initiality conjecture. He will be using this library +to do so. diff --git a/doc/implementation.tex b/doc/implementation.tex index 51f5629..e8574de 100644 --- a/doc/implementation.tex +++ b/doc/implementation.tex @@ -15,75 +15,75 @@ link\footnote{% }: % \begin{center} -\doclink + \doclink \end{center} The concepts formalized in this development are: % \begin{center} -\begin{tabular}{ l l } -Name & Module \\ -\hline -Equivalences & \sourcelink{Cat.Equivalence} \\ -Categories & \sourcelink{Cat.Category} \\ -Functors & \sourcelink{Cat.Category.Functor} \\ -Products & \sourcelink{Cat.Category.Product} \\ -Exponentials & \sourcelink{Cat.Category.Exponential} \\ -Cartesian closed categories & \sourcelink{Cat.Category.CartesianClosed} \\ -Natural transformations & \sourcelink{Cat.Category.NaturalTransformation} \\ -Yoneda embedding & \sourcelink{Cat.Category.Yoneda} \\ -Monads & \sourcelink{Cat.Category.Monad} \\ -Kleisli Monads & \sourcelink{Cat.Category.Monad.Kleisli} \\ -Monoidal Monads & \sourcelink{Cat.Category.Monad.Monoidal} \\ -Voevodsky's construction & \sourcelink{Cat.Category.Monad.Voevodsky} \\ -Opposite category & \sourcelink{Cat.Categories.Opposite} \\ -Category of sets & \sourcelink{Cat.Categories.Sets} \\ -Span category & \sourcelink{Cat.Categories.Span} \\ -\end{tabular} + \begin{tabular}{ l l } + Name & Module \\ + \hline + Equivalences & \sourcelink{Cat.Equivalence} \\ + Categories & \sourcelink{Cat.Category} \\ + Functors & \sourcelink{Cat.Category.Functor} \\ + Products & \sourcelink{Cat.Category.Product} \\ + Exponentials & \sourcelink{Cat.Category.Exponential} \\ + Cartesian closed categories & \sourcelink{Cat.Category.CartesianClosed} \\ + Natural transformations & \sourcelink{Cat.Category.NaturalTransformation} \\ + Yoneda embedding & \sourcelink{Cat.Category.Yoneda} \\ + Monads & \sourcelink{Cat.Category.Monad} \\ + Kleisli Monads & \sourcelink{Cat.Category.Monad.Kleisli} \\ + Monoidal Monads & \sourcelink{Cat.Category.Monad.Monoidal} \\ + Voevodsky's construction & \sourcelink{Cat.Category.Monad.Voevodsky} \\ + Opposite category & \sourcelink{Cat.Categories.Opposite} \\ + Category of sets & \sourcelink{Cat.Categories.Sets} \\ + Span category & \sourcelink{Cat.Categories.Span} \\ + \end{tabular} \end{center} % \begin{samepage} -Furthermore the following items have been partly formalized: -% -\begin{center} -\begin{tabular}{ l l } -Name & Module \\ -\hline -Category of categories & \sourcelink{Cat.Categories.Cat} \\ -Category of relations & \sourcelink{Cat.Categories.Rel} \\ -Category of functors & \sourcelink{Cat.Categories.Fun} \\ -Free category & \sourcelink{Cat.Categories.Free} \\ -Monoids & \sourcelink{Cat.Category.Monoid} \\ -\end{tabular} -\end{center} + Furthermore the following items have been partly formalized: + % + \begin{center} + \begin{tabular}{ l l } + Name & Module \\ + \hline + Category of categories & \sourcelink{Cat.Categories.Cat} \\ + Category of relations & \sourcelink{Cat.Categories.Rel} \\ + Category of functors & \sourcelink{Cat.Categories.Fun} \\ + Free category & \sourcelink{Cat.Categories.Free} \\ + Monoids & \sourcelink{Cat.Category.Monoid} \\ + \end{tabular} + \end{center} \end{samepage}% % -As well as a range of various results about these. E.g.\ I have shown -that the category of sets has products. In the following I aim to +As well as a range of various results about these. E.g.\ I have shown +that the category of sets has products. In the following I aim to demonstrate some of the techniques employed in this formalization and in the interest of brevity I will not detail all the things I have -formalized. In stead I have selected parts of this formalization that +formalized. In stead I have selected parts of this formalization that highlight some interesting proof techniques relevant to doing proofs -in Cubical Agda. This chapter will focus on the definition of +in Cubical Agda. This chapter will focus on the definition of \emph{categories}, \emph{equivalences}, the \emph{opposite category}, the \emph{category of sets}, \emph{products}, the \emph{span category} and the two formulations of \emph{monads}. One technique employed throughout this formalization is the idea of -distinguishing types with more or less homotopical structure. To do +distinguishing types with more or less homotopical structure. To do this I have followed the following design-principle: I have split concepts up into things that represent \emph{data} and \emph{laws} -about this data. The idea is that we can provide a proof that the laws -are mere propositions. As an example a category is defined to have two +about this data. The idea is that we can provide a proof that the laws +are mere propositions. As an example a category is defined to have two members: $\var{raw}$ which is a collection of the data and $\var{isCategory}$ which asserts some laws about that data. This allows me to reason about things in a more ``standard mathematical way'', where one can reason about two categories by -simply focusing on the data. This is achieved by creating a function +simply focusing on the data. This is achieved by creating a function embodying the equality principle for a given type. -For the rest of this chapter I will present some of these results. For -didactic reasons no source-code has been included in this chapter. To +For the rest of this chapter I will present some of these results. For +didactic reasons no source-code has been included in this chapter. To see the formal definitions the reader is referred to the implementation which is linked in the tables above. @@ -91,64 +91,64 @@ implementation which is linked in the tables above. \label{sec:categories} The data for a category consist of a type for the sort of objects; a type for the sort of arrows; an identity arrow and a composition -operation for arrows. Another record encapsulates some laws about +operation for arrows. Another record encapsulates some laws about this data: associativity of composition, identity law for the identity -morphism. These are standard constituents of a category and can be -found in typical mathematical expositions on the topic. We shall +morphism. These are standard constituents of a category and can be +found in typical mathematical expositions on the topic. We shall impose one further requirement on what it means to be a category, namely that the type of arrows form a set. -Such categories are called \nomen{1-categories}{1-category}. It is -possible to relax this requirement. This would lead to the notion of -higher categories (\cite[p. 307]{hott-2013}). For the purpose of this +Such categories are called \nomen{1-categories}{1-category}. It is +possible to relax this requirement. This would lead to the notion of +higher categories (\cite[p. 307]{hott-2013}). For the purpose of this thesis however, this report will restrict itself to -1-categories\index{1-category}. Generalizing this work to higher +1-categories\index{1-category}. Generalizing this work to higher categories would be a very natural extension of this work. Raw categories satisfying all of the above requirements are called a -\nomenindex{pre-categories}. As a further requirement to be a proper category we -require it to be univalent. Before we can define this, I must introduce two more +\nomenindex{pre-categories}. As a further requirement to be a proper category we +require it to be univalent. Before we can define this, I must introduce two more definitions: If we let $p$ be a witness to the identity law, which formally is: % \begin{equation} \label{eq:identity} \var{IsIdentity} ≜ ∏_{A, B \tp \Object} ∏_{f \tp \Arrow\ A\ B} - \left(\id \lll f ≡ f\right) \x \left(f \lll \id ≡ f\right) + \left(\id \lll f ≡ f\right) \x \left(f \lll \id ≡ f\right) \end{equation} % Then we can construct the identity isomorphism $\idIso \tp (\identity, -\identity, p) \tp A ≊ A$ for any object $A$. Here $≊$ +\identity, p) \tp A ≊ A$ for any object $A$. Here $≊$ denotes isomorphism on objects (whereas $\cong$ denotes isomorphism on -types). This will be elaborated further on in sections -\S\ref{sec:equiv} and \S\ref{sec:univalence}. Moreover due to +types). This will be elaborated further on in sections +\S\ref{sec:equiv} and \S\ref{sec:univalence}. Moreover due to substitution for paths we can construct an isomorphism from \emph{any} path: % \begin{equation} -\idToIso \tp A ≡ B → A ≊ B + \idToIso \tp A ≡ B → A ≊ B \end{equation} % The univalence criterion for categories states that this map must be an -equivalence. The requirement is similar to univalence for types, but where -isomorphism on objects play the role of equivalence on types. Formally: +equivalence. The requirement is similar to univalence for types, but where +isomorphism on objects play the role of equivalence on types. Formally: % \begin{align} -\label{eq:cat-univ} -\isEquiv\ (A ≡ B)\ (A ≊ B)\ \idToIso + \label{eq:cat-univ} + \isEquiv\ (A ≡ B)\ (A ≊ B)\ \idToIso \end{align} % Note that \ref{eq:cat-univ} is \emph{not} the same as: % \begin{equation} -\label{eq:cat-univalence} -%% \tag{Univalence, category} -(A ≡ B) ≃ (A ≊ B) + \label{eq:cat-univalence} + %% \tag{Univalence, category} + (A ≡ B) ≃ (A ≊ B) \end{equation} % However the two are logically equivalent: One can construct the latter from the former simply by ``forgetting'' that $\idToIso$ plays the -role of the equivalence. The other direction is more involved and will +role of the equivalence. The other direction is more involved and will be discussed in section \S\ref{sec:univalence}. In summary the definition of a category is the following collection of @@ -164,54 +164,54 @@ data: And laws: % \begin{align} -%% \tag{associativity} -h \lll (g \lll f) ≡ (h \lll g) \lll f \\ -%% \tag{identity} -\left( -\identity \lll f ≡ f -\right) -\x -\left( -f \lll \identity ≡ f -\right) -\\ -\label{eq:arrows-are-sets} -%% \tag{arrows are sets} -\isSet\ (\Arrow\ A\ B)\\ -\tag{\ref{eq:cat-univ}} -\isEquiv\ (A ≡ B)\ (A ≊ B)\ \idToIso + %% \tag{associativity} + h \lll (g \lll f) ≡ (h \lll g) \lll f \\ + %% \tag{identity} + \left( + \identity \lll f ≡ f + \right) + \x + \left( + f \lll \identity ≡ f + \right) + \\ + \label{eq:arrows-are-sets} + %% \tag{arrows are sets} + \isSet\ (\Arrow\ A\ B)\\ + \tag{\ref{eq:cat-univ}} + \isEquiv\ (A ≡ B)\ (A ≊ B)\ \idToIso \end{align} % -$\lll$ denotes arrow composition (right-to-left), and reverse function -composition (left-to-right, diagrammatic order) is denoted $\rrr$. The objects -($A$, $B$ and $C$) and arrow ($f$, $g$, $h$) are implicitly universally -quantified. +The function $\lll$ denotes arrow composition (right-to-left), and +reverse function composition (left-to-right, diagrammatic order) is +denoted $\rrr$. The objects ($A$, $B$ and $C$) and arrow ($f$, $g$, +$h$) are implicitly universally quantified. With all this in place it is now possible to prove that all the laws -are indeed mere propositions. Most of the proofs simply use the fact -that the type of arrows are sets. This is because most of the laws are -a collection of equations between arrows in the category. And since +are indeed mere propositions. Most of the proofs simply use the fact +that the type of arrows are sets. This is because most of the laws are +a collection of equations between arrows in the category. And since such a proof does not have any content exactly because the type of -arrows form a set, two witnesses must be the same. All the proofs are -really quite mechanical. Let us have a look at one of them: Proving +arrows form a set, two witnesses must be the same. All the proofs are +really quite mechanical. Let us have a look at one of them: Proving that \ref{eq:identity} is a mere proposition: % \begin{equation} \isProp\ \var{IsIdentity} \end{equation} % -There are multiple ways to do this. Perhaps one of the more intuitive proofs +There are multiple ways to do this. Perhaps one of the more intuitive proofs is by way of the `combinators' $\propPi$ and $\propSig$ presented in sections \S\ref{sec:propPi} and \S\ref{sec:propSig}: % \begin{align*} -\propPi & \tp \left(∏_{a \tp A} \isProp\ (P\ a)\right) → \isProp\ \left(∏_{a \tp A} P\ a\right) + \propPi & \tp \left(∏_{a \tp A} \isProp\ (P\ a)\right) → \isProp\ \left(∏_{a \tp A} P\ a\right) \\ -\propSig & \tp \isProp\ A → \left(∏_{a \tp A} \isProp\ (P\ a)\right) → \isProp\ \left(∑_{a \tp A} P\ a\right) + \propSig & \tp \isProp\ A → \left(∏_{a \tp A} \isProp\ (P\ a)\right) → \isProp\ \left(∑_{a \tp A} P\ a\right) \end{align*} % The proof goes like this: We `eliminate' the 3 function abstractions -by applying $\propPi$ three times. So our proof obligation becomes: +by applying $\propPi$ three times. So our proof obligation becomes: % $$ \isProp\ \left( \left( \id \comp f ≡ f \right) \x \left( f \comp \id ≡ f \right) \right) @@ -223,30 +223,30 @@ us the two obligations $\isProp\ (\id \comp f ≡ f)$ and $\isProp\ (f \comp set. This example illustrates nicely how we can use these combinators to -reason about `canonical' types like $∑$ and $∏$. Similar -combinators can be defined at the other homotopic levels. These +reason about `canonical' types like $∑$ and $∏$. Similar +combinators can be defined at the other homotopic levels. These combinators are however not applicable in situations where we want to -reason about other types e.g.\ types we have defined ourselves. For +reason about other types e.g.\ types we have defined ourselves. For instance, after we have proven that all the projections of pre-categories are propositions, we would like to bundle this up to -show that the type of pre-categories is also a proposition. Formally: +show that the type of pre-categories is also a proposition. Formally: % \begin{equation} -\label{eq:propIsPreCategory} -\isProp\ \IsPreCategory + \label{eq:propIsPreCategory} + \isProp\ \IsPreCategory \end{equation} % Where the definition of $\IsPreCategory$ is the triple: % \begin{align*} -\var{isAssociative} & \tp \var{IsAssociative}\\ -\isIdentity & \tp \var{IsIdentity}\\ -\var{arrowsAreSets} & \tp \var{ArrowsAreSets} + \var{isAssociative} & \tp \var{IsAssociative}\\ + \isIdentity & \tp \var{IsIdentity}\\ + \var{arrowsAreSets} & \tp \var{ArrowsAreSets} \end{align*} % -Each corresponding to the first three laws for categories. Note that +Each corresponding to the first three laws for categories. Note that since $\IsPreCategory$ is not formulated with a chain of sigma-types -we will not have any combinators available to help us here. In stead +we will not have any combinators available to help us here. In stead the path type must be used directly. The type \ref{eq:propIsPreCategory} is judgmentally the same as: @@ -255,14 +255,14 @@ $$ ∏_{a, b \tp \IsPreCategory} a ≡ b $$ % -So to prove the proposition let $a, b \tp \IsPreCategory$ be given. To +So to prove the proposition let $a, b \tp \IsPreCategory$ be given. To prove the equality $a ≡ b$ is to give a continuous path from the -index-type into the path-space. I.e.\ a function $\I → -\IsPreCategory$. This path must satisfy being being judgmentally the -same as $a$ at the left endpoint and $b$ at the right endpoint. We +index-type into the path-space. I.e.\ a function $\I → +\IsPreCategory$. This path must satisfy being being judgmentally the +same as $a$ at the left endpoint and $b$ at the right endpoint. We know we can form a continuous path between all projections of $a$ and $b$, this follows from the type of all the projections being mere -propositions. For instance, the path between $a.\isIdentity$ and +propositions. For instance, the path between $a.\isIdentity$ and $b.\isIdentity$ is simply formed by: % $$ @@ -274,45 +274,44 @@ $$ So to give the continuous function $\I → \IsPreCategory$, which is our goal, we introduce $i \tp \I$ and proceed by constructing an element of $\IsPreCategory$ by using the fact that all the projections are propositions to generate paths -between all projections. Once we have such a path e.g.\ $p \tp a.\isIdentity +between all projections. Once we have such a path e.g.\ $p \tp a.\isIdentity ≡ b.\isIdentity$ we can eliminate it with $i$ and thus obtain $p\ i \tp -(p\ i).\isIdentity$. This element satisfies exactly that it corresponds to the -corresponding projections at either endpoint. Thus the element we construct at +(p\ i).\isIdentity$. This element satisfies exactly that it corresponds to the +corresponding projections at either endpoint. Thus the element we construct at $i$ becomes the triple: % \begin{equation} -\label{eq:proof-prop-IsPreCategory} -\begin{aligned} - & \var{propIsAssociative} && a.\var{isAssociative}\ - && b.\var{isAssociative} && i \\ - & \propIsIdentity && a.\isIdentity\ - && b.\isIdentity && i \\ - & \var{propArrowsAreSets} && a.\var{arrowsAreSets}\ - && b.\var{arrowsAreSets} && i -\end{aligned} + \label{eq:proof-prop-IsPreCategory} + \begin{aligned} + & \var{propIsAssociative} && a.\var{isAssociative}\ + && b.\var{isAssociative} && i \\ + & \propIsIdentity && a.\isIdentity\ + && b.\isIdentity && i \\ + & \var{propArrowsAreSets} && a.\var{arrowsAreSets}\ + && b.\var{arrowsAreSets} && i + \end{aligned} \end{equation} % I have found this to be a general pattern when proving things in homotopy type theory, namely that you have to wrap and unwrap -equalities at different levels. It is worth noting that proving this +equalities at different levels. It is worth noting that proving this theorem with the regular inductive equality type would already not be possible, since we at least need functional extensionality\index{functional extensionality} (the projections are -all $∏$-types). Assuming we had functional extensionality -available to us as an axiom, we would use functional extensionality -\TODO{in reverse?} to retrieve the equalities in $a$ and $b$, -pattern-match on them to see that they are both $\refl$ and then close -the proof with $\refl$. Of course this theorem is not so interesting -in the setting of ITT since we know a priori that equality proofs are -unique. +all $∏$-types). Assuming we had functional extensionality available to +us as an axiom, we would use functional extensionality to retrieve the +equalities in $a$ and $b$; pattern match on them to see that they are +both $\refl$ and then close the proof with $\refl$. Of course this +theorem is not so interesting in the setting of ITT since we know +a~priori that equality proofs are unique. The situation is a bit more complicated when we have a dependent type. -For instance, when we want to show that $\IsCategory$ is a mere -proposition. The type $\IsCategory$ is a record with two fields, a -witness to being a pre-category and the univalence condition. Recall -that the univalence condition is indexed by the identity-proof. So to +For instance when we want to show that $\IsCategory$ is a mere +proposition. The type $\IsCategory$ is a record with two fields, a +witness of being a pre-category and the univalence condition. Recall +that the univalence condition is indexed by the identity-proof. So to follow the same recipe as above, let $a, b \tp \IsCategory$ be given, -to show them equal, we now need to give two paths. One homogeneous: +to show them equal, we now need to give two paths. One homogeneous: % $$ p \tp a.\isPreCategory ≡ b.\isPreCategory @@ -324,28 +323,38 @@ $$ \Path\ (\lambda\; i → (p\ i).Univalent)\ a.\isPreCategory\ b.\isPreCategory $$ % -Which depends on the choice of $p$. The first of these we can provide since, as -we have shown, $\IsPreCategory$ is a proposition. However, even though -$\Univalent$ is also a proposition, we cannot use this directly to show the -latter. This is because $\isProp$ talks about non-dependent paths. So we need to -'promote' the result that univalence is a proposition to a heterogeneous path. -To this end we can use $\lemPropF$, which was introduced in \S\ref{sec:lemPropF}. +This path depends on the choice of $p$. The first of these we can +provide since, as we have shown, $\IsPreCategory$ is a +proposition. However, even though $\Univalent$ is also a proposition, +we cannot use this directly to show the latter. This is because +$\isProp$ talks about non-dependent paths. So we need to 'promote' the +result that univalence is a proposition to a heterogeneous path. To +this end we can use $\lemPropF$, which was introduced in +\S\ref{sec:lemPropF}. -In this case $A = \var{IsIdentity}\ \identity$ and $B = \Univalent$. We have -shown that being a category is a proposition, a result that holds for any choice -of identity proof. Finally we must provide a proof that the identity proofs at -$a$ and $b$ are indeed the same, this we can extract from $p$ by applying -congruence of paths: +In this case $A = \var{IsIdentity}\ \identity$ and $B = +\Univalent$. We have shown that being a category is a proposition, a +result that holds for any choice of identity proof so it will also +hold for the witness obtained at an arbitrary point along $p$. Finally +we must provide a proof that the identity proofs at $a$ and $b$ are +indeed the same, this we can extract from $p$ by applying congruence +of paths: % $$ \congruence\ \isIdentity\ p $$ % +In summary the heterogeneous path is inhabited by: +% +$$ +\var{lemPropF}\ \var{propUnivalent}\ (\var{cong}\ p.\var{isIdentity}) +$$ +% And this finishes the proof that being-a-category is a mere proposition (\ref{eq:propIsPreCategory}). When we have a proper category we can make precise the notion of -``identifying isomorphic types''. That is, we can construct the +``identifying isomorphic types''. That is, we can construct the function: % $$ @@ -356,17 +365,17 @@ A perhaps somewhat surprising application of this is that we can show that terminal objects are propositional: % \begin{align} -\label{eq:termProp} -\isProp\ \var{Terminal} + \label{eq:termProp} + \isProp\ \var{Terminal} \end{align} % It follows from the usual observation that any two terminal objects are -isomorphic - and since categories are univalent, so are they equal. The proof is +isomorphic - and since categories are univalent, so are they equal. The proof is omitted here, but the curious reader can check the implementation for the -details. It is in the module: +details. It is in the module: % \begin{center} -\sourcelink{Cat.Category} + \sourcelink{Cat.Category} \end{center} \section{Equivalences} @@ -374,38 +383,39 @@ details. It is in the module: The usual notion of a function $f \tp A → B$ having an inverses is: % \begin{equation} -\label{eq:isomorphism} -∑_{g \tp B → A} \left( f \comp g ≡ \identity \right) \x \left( g \comp f ≡ \identity \right) + \label{eq:isomorphism} + ∑_{g \tp B → A} \left( f \comp g ≡ \identity \right) \x \left( g \comp f ≡ \identity \right) \end{equation} % This is defined in \cite[p. 129]{hott-2013} where it is referred to as the a -``quasi-inverse''. We shall refer to the type \ref{eq:isomorphism} as -$\Isomorphism\ f$. This also gives rise to the following type: +``quasi-inverse''. We shall refer to the type \ref{eq:isomorphism} as +$\Isomorphism\ f$. This also gives rise to the following type: % \begin{equation} -A \cong B ≜ ∑_{f \tp A → B} \Isomorphism\ f + A \cong B ≜ ∑_{f \tp A → B} \Isomorphism\ f \end{equation} % At the same place \cite{hott-2013} gives an ``interface'' for what the judgment $\isEquiv \tp (A → B) → \MCU$ must provide: % \begin{align} -\var{fromIso} & \tp \Isomorphism\ f → \isEquiv\ f \\ -\var{toIso} & \tp \isEquiv\ f → \Isomorphism\ f \\ -\label{eq:propIsEquiv} - &\mathrel{\ } \isEquiv\ f + \var{fromIso} & \tp \Isomorphism\ f → \isEquiv\ f \\ + \var{toIso} & \tp \isEquiv\ f → \Isomorphism\ f \\ + \label{eq:propIsEquiv} + &\mathrel{\ } \isEquiv\ f \end{align} % The maps $\var{fromIso}$ and $\var{toIso}$ naturally extend to these maps: % \begin{align} -\var{fromIsomorphism} & \tp A \cong B → A ≃ B \\ -\var{toIsomorphism} & \tp A ≃ B → A \cong B + \var{fromIsomorphism} & \tp A \cong B → A ≃ B \\ + \var{toIsomorphism} & \tp A ≃ B → A \cong B \end{align} % -Having this interface gives us both: a way to think rather abstractly about how -to work with equivalences and a way to use ad hoc definitions of equivalences. -The specific instantiation of $\isEquiv$ as defined in \cite{cubical-agda} is: +Having this interface gives us both a way to think rather abstractly +about how to work with equivalences and a way to use ad~hoc +definitions of equivalences. The specific instantiation of $\isEquiv$ +as defined in \cite{cubical-agda} is: % $$ isEquiv\ f ≜ ∏_{b \tp B} \isContr\ (\fiber\ f\ b) @@ -420,7 +430,7 @@ move away from this specific instantiation and think about it more abstractly once we have shown that this definition actually works as an equivalence. The implementation of $\var{fromIso}$ can be found in -\cite{cubical-agda} where it is known as $\var{gradLemma}$. The +\cite{cubical-agda} where it is known as $\var{gradLemma}$. The implementation of $\var{fromIso}$ as well as the proof that this equivalence is a proposition (\ref{eq:propIsEquiv}) can be found in my implementation. @@ -429,14 +439,14 @@ We say that two types $A\;B \tp \Type$ are equivalent exactly if there exists an equivalence between them: % \begin{equation} -\label{eq:equivalence} -A ≃ B ≜ ∑_{f \tp A → B} \isEquiv\ f + \label{eq:equivalence} + A ≃ B ≜ ∑_{f \tp A → B} \isEquiv\ f \end{equation} % Note that the term equivalence here is overloaded referring both to the map $f -\tp A → B$ and the type $A ≃ B$. The notion of an isomorphism is +\tp A → B$ and the type $A ≃ B$. The notion of an isomorphism is similarly conflated as isomorphism can refer to the type $A \cong B$ as well as -the the map $A → B$ that witness this. I will use these conflated terms when +the the map $A → B$ that witness this. I will use these conflated terms when it is clear from the context what is being referred to. Both $\cong$ and $≃$ form equivalence relations (no pun intended). @@ -468,20 +478,22 @@ $$ (A ≡ B) \cong (A ≊ B) $$ % -That is, we must demonstrate that there is an isomorphism (on types) between -equalities and isomorphisms (on arrows). It is worthwhile to dwell on this for a -few seconds. This type looks very similar to univalence for types and is -therefore perhaps a bit more intuitive to grasp the implications of. Of course -univalence for types (which is a proposition -- i.e.\ provable) does not imply -univalence of all pre-category since morphisms in a category are not regular -functions -- in stead they can be thought of as a generalization hereof. The univalence criterion therefore is simply a way of restricting arrows -to behave similarly to maps. +That is, we must demonstrate that there is an isomorphism (on types) +between equalities and isomorphisms (on arrows). It is worthwhile to +dwell on this for a few seconds. This type looks very similar to +univalence for types and is therefore perhaps a bit more intuitive to +grasp the implications of. Of course univalence for types (which is a +theorem -- i.e.\ provably holds) does not imply univalence of all +pre-category since morphisms in a category are not regular functions +-- in stead they can be thought of as a generalization hereof. The +univalence criterion therefore is simply a way of restricting arrows +to behave like maps with respect to univalence. I will now mention a few helpful theorems that follow from univalence that will become useful later. Obviously univalence gives us an isomorphism between $A ≡ B$ and $A -≊ B$. I will name these for convenience: +≊ B$. I will name these for convenience: % $$ \idToIso \tp A ≡ B → A ≊ B @@ -491,81 +503,91 @@ $$ \isoToId \tp A ≊ B → A ≡ B $$ % -The next few theorems are variations on theorem 9.1.9 from \cite{hott-2013}. Let -an isomorphism $A ≊ B$ in some category $\bC$ be given. Name the -isomorphism $\iota \tp A → B$ and its inverse $\inv{\iota} \tp B → A$. -Since $\bC$ is a category (and therefore univalent) the isomorphism induces a -path $p \tp A ≡ B$. From this equality we can get two further paths: -$p_{\var{dom}} \tp \Arrow\ A\ X ≡ \Arrow\ B\ X$ and -$p_{\var{cod}} \tp \Arrow\ X\ A ≡ \Arrow\ X\ B$. We -then have the following two theorems: +The next few theorems are variations on theorem 9.1.9 from +\cite{hott-2013}. Let an isomorphism $A ≊ B$ in some category $\bC$ be +given. Name the isomorphism $\iota \tp A → B$ and its inverse +$\inv{\iota} \tp B → A$. Since $\bC$ is a category (and therefore +univalent) the isomorphism induces a path +% +$$p \defeq \idToIso\ (\iota, \inv{\iota}, \dots) \tp A ≡ B$$ +% +From this equality we can get two further paths: +% +\begin{align*} + p_{\var{dom}} & \tp \Arrow\ A\ X ≡ \Arrow\ B\ X \\ + p_{\var{cod}} & \tp \Arrow\ X\ A ≡ \Arrow\ X\ B +\end{align*} +% +We then have the following two theorems: % \begin{align} -\label{eq:coeDom} -\var{coeDom} & \tp ∏_{f \tp A → X} -\var{coe}\ p_{\var{dom}}\ f ≡ f \lll \inv{\iota} -\\ -\label{eq:coeCod} -\var{coeCod} & \tp ∏_{f \tp A → X} -\var{coe}\ p_{\var{cod}}\ f ≡ \iota \lll f + \label{eq:coeDom} + \var{coeDom} & \tp ∏_{f \tp A → X} + \var{coe}\ p_{\var{dom}}\ f ≡ f \lll \inv{\iota} + \\ + \label{eq:coeCod} + \var{coeCod} & \tp ∏_{f \tp A → X} + \var{coe}\ p_{\var{cod}}\ f ≡ \iota \lll f \end{align} % I will give the proof of the first theorem here, the second one is analogous. % \begin{align*} -\var{coe}\ p_{\var{dom}}\ f - & ≡ f \lll \inv{(\idToIso\ p)} && \text{lemma} \\ + \var{coe}\ p_{\var{dom}}\ f + & ≡ f \lll (\idToIso\ p)_2 && \text{lemma} \\ & ≡ f \lll \inv{\iota} - && \text{$\idToIso$ and $\isoToId$ are inverses}\\ + && \text{$\idToIso$ and $\isoToId$ are inverses}\\ \end{align*} % -In the second step we use the fact that $p$ is constructed from the isomorphism -$\iota$ -- $\inv{(\idToIso\ p)}$ denotes the map $B → A$ induced by the -isomorphism $\idToIso\ p \tp A \cong B$. The helper-lemma is similar to -what we are trying to prove but talks about paths rather than isomorphisms: +In the second step we use the fact that $p$ is constructed from the +isomorphism $\iota$. The subscript in term $(\idToIso\ p)_2$ is +intended to denote the inverse map $B → A$ from the isomorphism +$\idToIso\ p \tp A \cong B$. The helper-lemma is similar to what we +are trying to prove but talks about paths rather than isomorphisms: % \begin{equation} -\label{eq:coeDomIso} -∏_{f \tp \Arrow\ A\ B} ∏_{p \tp A ≡ B} -\var{coe}\ p_{\var{dom}}\ f ≡ f \lll \inv{(\idToIso\ p)} + \label{eq:coeDomIso} + ∏_{f \tp \Arrow\ A\ B} ∏_{p \tp A ≡ B} + \var{coe}\ p_{\var{dom}}\ f ≡ f \lll (\idToIso\ p)_{2} \end{equation} % -Again $p_{\var{dom}}$ denotes the path $\Arrow\ A\ X ≡ -\Arrow\ B\ X$ induced by $p$. To prove this statement I let $f$ and $p$ be -given and then invoke based-path-induction. The induction will be based at $A -\tp \Object$ Let $\widetilde{B} \tp \Object$ and $\widetilde{p} \tp A -≡ \widetilde{B}$ be given. The family that we perform induction over will -be: +Again $p_{\var{dom}}$ denotes the path $\Arrow\ A\ X ≡ \Arrow\ B\ X$ +induced by $p$. To prove this statement let $f$ and $p$ be given then +we invoke based path induction. The induction will be based at $A \tp +\Object$ Let $\widetilde{B} \tp \Object$ and $\widetilde{p} \tp A ≡ +\widetilde{B}$ be given. The family that we perform induction over +will be: % \begin{align} -D\ \widetilde{B}\ \widetilde{p} ≜ + D\ \widetilde{B}\ \widetilde{p} ≜ %% ∏_{\widetilde{B} \tp \Object} %% ∏_{\widetilde{p} \tp A ≡ \widetilde{B}} - \var{coe}\ {\widetilde{p}}^*\ f -≡ -f \lll \inv{(\idToIso\ \widetilde{p})} + \var{coe}\ {\widetilde{p}_{\var{dom}}}\ f + ≡ + f \lll (\idToIso\ \widetilde{p})_{2} \end{align} The base-case therefore becomes -$d \tp \var{coe}\ \refl^*\ f ≡ f \lll \inv{(\idToIso\ \refl)}$ +$d \tp \var{coe}\ \refl_{\var{dom}}\ f ≡ f \lll (\idToIso\ \refl)_{2}$ and is inhabited by: \begin{align*} -\var{coe}\ \refl^*\ f -& ≡ f + \var{coe}\ \refl_{\var{dom}}\ f + & ≡ f && \text{$\refl$ is a neutral element for $\var{coe}$}\\ -& ≡ f \lll \identity \\ -& ≡ f \lll \var{subst}\ \refl\ \identity + & ≡ f \lll \identity \\ + & ≡ f \lll \var{subst}\ \refl\ \identity && \text{$\refl$ is a neutral element for $\var{subst}$}\\ -& ≡ f \lll \inv{(\idToIso\ \refl)} + & = f \lll (\idToIso\ \refl)_{2} && \text{By definition of $\idToIso$}\\ \end{align*} % -To close the based-path-induction we must supply the value ``at the other''. In -this case this is simply $B \tp \Object$ and $p \tp A ≡ B$ which we have. -In summary the proof of \ref{eq:coeDomIso} is the term: +To close the based-path-induction we must supply the value ``at the +other end''. In this case this is simply $B \tp \Object$ and $p \tp A +≡ B$ which we have. In summary the proof of \ref{eq:coeDomIso} is the +term: % \begin{equation} -\label{eq:pathJ-example} -\pathJ\ D\ d\ B\ p + \label{eq:pathJ-example} + \pathJ\ D\ d\ B\ p \end{equation} % And this finishes the proof of \ref{eq:coeDomIso} and thus \ref{eq:coeDom}. @@ -573,25 +595,25 @@ And this finishes the proof of \ref{eq:coeDomIso} and thus \ref{eq:coeDom}. \section{Categories} \subsection{Opposite category} \label{op-cat} -The first category I will present is a pure construction on categories. Given -some category we can construct its dual, called the opposite category. Starting +The first category I will present is a pure construction on categories. Given +some category we can construct its dual, called the opposite category. Starting with a simple example allows us to focus on how we work with equivalences and univalence in a very simple category where the structure of the category is rather simple. Let $\bC$ be some category, we then define the opposite category -$\bC^{\var{Op}}$. It has the same objects, but the type of arrows are flipped, +$\bC^{\var{Op}}$. It has the same objects, but the type of arrows are flipped, that is to say an arrow from $A$ to $B$ in the opposite category corresponds to -an arrow from $B$ to $A$ in the underlying category. The identity arrow is the -same as the one in the underlying category (they have the same type). Function +an arrow from $B$ to $A$ in the underlying category. The identity arrow is the +same as the one in the underlying category (they have the same type). Function composition will be reverse function composition from the underlying category. I will refer to things in terms of the underlying category, unless they have an -over-bar. So e.g.\ $\idToIso$ is a function in the underlying category and the +over-bar. So e.g.\ $\idToIso$ is a function in the underlying category and the corresponding thing is denoted $\wideoverbar{\idToIso}$ in the opposite category. -Showing that this forms a pre-category is rather straightforward. +Showing that this forms a pre-category is rather straightforward. % $$ h \rrr (g \rrr f) ≡ h \rrr g \rrr f @@ -607,85 +629,85 @@ $$ This is just the swapped version of identity. Finally, that the arrows form sets just follows by flipping the order of the -arguments. Or in other words; since $\Arrow\ A\ B$ is a set for all $A\;B \tp +arguments. Or in other words; since $\Arrow\ A\ B$ is a set for all $A\;B \tp \Object$ then so is $Arrow\ B\ A$. -Now, to show that this category is univalent is not as straightforward. Luckily -section \S\ref{sec:equiv} gave us some tools to work with equivalences. We saw +Now, to show that this category is univalent is not as straightforward. Luckily +section \S\ref{sec:equiv} gave us some tools to work with equivalences. We saw that we can prove this category univalent by giving an inverse to $\wideoverbar{\idToIso} \tp (A ≡ B) → (A \wideoverbar{≊} B)$. From the original category we have that $\idToIso \tp (A ≡ B) → (A \cong -B)$ is an isomorphism. Let us denote its inverse with $\isoToId \tp (A -≊ B) → (A ≡ B)$. If we squint we can see what we need is a way to +B)$ is an isomorphism. Let us denote its inverse with $\isoToId \tp (A +≊ B) → (A ≡ B)$. If we squint we can see what we need is a way to go between $\wideoverbar{≊}$ and $≊$. -An inhabitant of $A ≊ B$ is simply an arrow $f \tp \Arrow\ A\ B$ -and its inverse $g \tp \Arrow\ B\ A$. In the opposite category $g$ will -play the role of the isomorphism and $f$ will be the inverse. Similarly we can -go in the opposite direction. I name these maps $\shufflef \tp (A ≊ -B) → (A \wideoverbar{≊} B)$ and $\shufflef^{-1} \tp (A -\wideoverbar{≊} B) → (A ≊ B)$ respectively. +An inhabitant of $A ≊ B$ is simply an arrow $f \tp \Arrow\ A\ B$ and +its inverse $g \tp \Arrow\ B\ A$ (and a witness to them being +inverses). In the opposite category $g$ will play the role of the +isomorphism and $f$ will be the inverse. Similarly we can go in the +opposite direction. I name these maps $\shufflef \tp (A ≊ B) → (A +\wideoverbar{≊} B)$ and $\shufflef^{-1} \tp (A \wideoverbar{≊} B) → (A +≊ B)$ respectively. As the inverse of $\wideoverbar{\idToIso}$ I will pick $\wideoverbar{\isoToId} -≜ \isoToId \comp \shufflef$. The proof that they are inverses go as +≜ \isoToId \comp \shufflef$. The proof that they are inverses go as follows: % \begin{align*} -\wideoverbar{\isoToId} \comp \wideoverbar{\idToIso} & = -\isoToId \comp \shufflef \comp \wideoverbar{\idToIso} -\\ -%% ≡⟨ cong (λ \; φ → φ x) (cong (λ \; φ → η ⊙ shuffle ⊙ φ) (funExt lem)) ⟩ \\ -% -& ≡ -\isoToId \comp \shufflef \comp \inv{\shufflef} \comp \idToIso -&& \text{lemma} \\ -%% ≡⟨⟩ \\ -& ≡ -\isoToId \comp \idToIso -&& \text{$\shufflef$ is an isomorphism} \\ -& ≡ -\identity -&& \text{$\isoToId$ is an isomorphism} + \wideoverbar{\isoToId} \comp \wideoverbar{\idToIso} & = + \isoToId \comp \shufflef \comp \wideoverbar{\idToIso} + \\ + %% ≡⟨ cong (λ \; φ → φ x) (cong (λ \; φ → η ⊙ shuffle ⊙ φ) (funExt lem)) ⟩ \\ + % + & ≡ + \isoToId \comp \shufflef \comp \inv{\shufflef} \comp \idToIso + && \text{lemma} \\ + %% ≡⟨⟩ \\ + & ≡ + \isoToId \comp \idToIso + && \text{$\shufflef$ is an isomorphism} \\ + & ≡ + \identity + && \text{$\isoToId$ is an isomorphism} \end{align*} % The other direction is analogous. The lemma used in step 2 of this proof states that $\wideoverbar{idToIso} ≡ -\inv{\shufflef} \comp \idToIso$. This is a rather straightforward proof +\inv{\shufflef} \comp \idToIso$. This is a rather straightforward proof since being-an-inverse-of is a proposition, so it suffices to show that their first components are equal, but this holds judgmentally. -This finished the proof that the opposite category is in fact a category. Now, -to prove that that opposite-of is an involution we must show: +This finished the proof that the opposite category is in fact a category. Now, +to prove that opposite-of is an involution we must show: % $$ ∏_{\bC \tp \Category} \left(\bC^{\var{Op}}\right)^{\var{Op}} ≡ \bC $$ % -As we have seen the laws in $\left(\bC^{\var{Op}}\right)^{\var{Op}}$ get quite -involved\footnote{We have not even seen the full story because we have used - this `interface' for equivalences.}. Luckily since being-a-category is a mere -proposition, we need not concern ourselves with this bit when proving the above. -We can use the equality principle for categories that let us prove an equality -just by giving an equality on the data-part. So, given a category $\bC$ all we -must provide is the following proof: +The laws in $\left(\bC^{\var{Op}}\right)^{\var{Op}}$ get quite +involved. Luckily since being-a-category is a mere proposition, we +need not concern ourselves with this bit when proving the above. We +can use the equality principle for categories that let us prove an +equality just by giving an equality on the data-part. So, given a +category $\bC$ all we must provide is the following proof: % $$ \var{raw}\ \left(\bC^{\var{Op}}\right)^{\var{Op}} ≡ \var{raw}\ \bC $$ % -And these are judgmentally the same. I remind the reader that the left-hand side +And these are judgmentally the same. I remind the reader that the left-hand side is constructed by flipping the arrows, which judgmentally is an involution. \subsection{Category of sets} The category of sets has as objects, not types, but only those types that are -homotopic sets. This is encapsulated in Agda with the following type: +homotopic sets. This is encapsulated in Agda with the following type: % $$\Set ≜ ∑_{A \tp \MCU} \isSet\ A$$ % The more straightforward notion of a category where the objects are types is -not a valid \mbox{(1-)category}. This stems from the fact that types in cubical -Agda types can have higher homotopic structure. +not a valid \mbox{(1-)category}. This stems from the fact that types in cubical +Agda can have higher homotopic structure. Univalence does not follow immediately from univalence for types: % @@ -693,7 +715,7 @@ $$(A ≡ B) ≃ (A ≃ B)$$ % Because here $A, B \tp \Type$ whereas the objects in this category have the type $\Set$ so we cannot form the type $\var{hA} ≃ \var{hB}$ for objects -$\var{hA}\;\var{hB} \tp \Set$. In stead I show that this category +$\var{hA}\;\var{hB} \tp \Set$. In stead I show that this category satisfies: % $$ @@ -701,96 +723,95 @@ $$ $$ % Which, as we saw in section \S\ref{sec:univalence}, is sufficient to show that the -category is univalent. The way that I have shown this is with a three-step -process. For objects $(A, s_A)\; (B, s_B) \tp \Set$ I show the following chain +category is univalent. The way that I have shown this is with a three-step +process. For objects $(A, s_A), (B, s_B) \tp \Set$ I show the following chain of equivalences: % \begin{align*} -((A, s_A) ≡ (B, s_B)) - & ≃ (A ≡ B) && \ref{eq:equivPropSig} \\ - & ≃ (A ≃ B) && \text{Univalence} \\ - & ≃ ((A, s_A) ≊ (B, s_B)) && \text{\ref{eq:equivSig} and \ref{eq:equivIso}} + ((A, s_A) ≡ (B, s_B)) + & ≃ (A ≡ B) && \ref{eq:equivPropSig} \\ + & ≃ (A ≃ B) && \text{Univalence} \\ + & ≃ ((A, s_A) ≊ (B, s_B)) && \text{\ref{eq:equivSig} and \ref{eq:equivIso}} \end{align*} And since $≃$ is an equivalence relation we can chain these equivalences -together. Step one will be proven with the following lemma: +together. Step one will be proven with the lemma: % \begin{align} \label{eq:equivPropSig} -\left(∏_{a \tp A} \isProp\ (P\ a)\right) → ∏_{x\;y \tp ∑_{a \tp A} P\ a} (x ≡ y) ≃ (\fst\ x ≡ \fst\ y) + \left(∏_{a \tp A} \isProp\ (P\ a)\right) → ∏_{x\;y \tp ∑_{a \tp A} P\ a} (x ≡ y) ≃ (\fst\ x ≡ \fst\ y) \end{align} % -The lemma states that for pairs whose second component are mere propositions -equality is equivalent to equality of the first components. In this case the -type-family $P$ is $\isSet$ which itself is a proposition for any type $A \tp -\Type$. Step two is univalence. Step three will be proven with the following -lemma: +The lemma states that for pairs whose second component are mere +propositions equality is equivalent to equality of the first +components. In this case the type-family $P$ is $\isSet$ which itself +is a proposition for any type $A \tp \Type$. Step two is univalence +for types. Step three will be proven with the following lemma: % \begin{align} \label{eq:equivSig} -∏_{a \tp A} \left( P\ a ≃ Q\ a \right) → ∑_{a \tp A} P\ a ≃ ∑_{a \tp A} Q\ a + ∏_{a \tp A} \left( P\ a ≃ Q\ a \right) → ∑_{a \tp A} P\ a ≃ ∑_{a \tp A} Q\ a \end{align} % Which says that if two type-families are equivalent at all points, then pairs with identical first components and these families as second components will -also be equivalent. For our purposes $P ≜ \isEquiv\ A\ B$ and $Q ≜ -\Isomorphism$. So we must finally prove: +also be equivalent. For our purposes $P ≜ \isEquiv\ A\ B$ and $Q ≜ +\Isomorphism$. So we must finally prove: % \begin{align} \label{eq:equivIso} -∏_{f \tp A → B} \left( \isEquiv\ A\ B\ f ≃ \Isomorphism\ f \right) + ∏_{f \tp A → B} \left( \isEquiv\ A\ B\ f ≃ \Isomorphism\ f \right) \end{align} -First, lets prove \ref{eq:equivPropSig}: Let $propP \tp ∏_{a \tp A} \isProp\ (P\ a)$ and $x\;y \tp ∑_{a \tp A} P\ a$ be given. Because +First, lets prove \ref{eq:equivPropSig}: Let $propP \tp ∏_{a \tp A} \isProp\ (P\ a)$ and $x\;y \tp ∑_{a \tp A} P\ a$ be given. Because of $\var{fromIsomorphism}$ it suffices to give an isomorphism between $x ≡ y$ and $\fst\ x ≡ \fst\ y$: % %% FIXME: Too much alignement? \begin{equation*} -\begin{aligned} - f & ≜ \congruence\ \fst + \begin{aligned} + f & ≜ \congruence\ \fst && \tp x ≡ y && → \fst\ x ≡ \fst\ y \\ - g & ≜ \var{lemSig}\ \var{propP}\ x\ y + g & ≜ \var{lemSig}\ \var{propP}\ x\ y && \tp \fst\ x ≡ \fst\ y && → x ≡ y -\end{aligned} + \end{aligned} \end{equation*} % -\TODO{Is it confusing that I use point-free style here?}Here $\var{lemSig}$ is -a lemma that says that if the second component of a pair is a proposition, it -suffices to give a path between its first components to construct an equality of -the two pairs: +Here $\var{lemSig}$ is a lemma that says that if the second component +of a pair is a proposition, it suffices to give a path between its +first components to construct an equality of the two pairs: % \begin{align*} -\var{lemSig} \tp \left( ∏_{x \tp A} \isProp\ (B\ x) \right) → -∏_{u\; v \tp ∑_{a \tp A} B\ a} + \var{lemSig} \tp \left( ∏_{x \tp A} \isProp\ (B\ x) \right) → + ∏_{u\; v \tp ∑_{a \tp A} B\ a} \left( \fst\ u ≡ \fst\ v \right) → u ≡ v \end{align*} % -The proof that these are indeed inverses has been omitted. The details -can be found in the module: +The proof that these are indeed inverses of one another has been +omitted. The details can be found in the module: \begin{center} -\sourcelink{Cat.Categories.Sets} + \sourcelink{Cat.Categories.Sets} \end{center} Now to prove \ref{eq:equivSig}: Let $e \tp ∏_{a \tp A} \left( P\ a -≃ Q\ a \right)$ be given. To prove the equivalence, it suffices +≃ Q\ a \right)$ be given. To prove the equivalence it suffices to give an isomorphism between $∑_{a \tp A} P\ a$ and $∑_{a \tp A} Q\ a$, but since they have identical first components it suffices to give an isomorphism between $P\ a$ and $Q\ a$ for all $a \tp A$. This is exactly what we can get from the equivalence $e$.\QED -Lastly we prove \ref{eq:equivIso}. Let $f \tp A → B$ be given. For the maps we +Lastly we prove \ref{eq:equivIso}. Let $f \tp A → B$ be given. For the maps we choose: % \begin{align*} -\var{toIso} + \var{toIso} & \tp \isEquiv\ f → \Isomorphism\ f \\ -\var{fromIso} + \var{fromIso} & \tp \Isomorphism\ f → \isEquiv\ f \end{align*} % -As mentioned in section \S\ref{sec:equiv}. These maps are not in general inverses -of each other. In stead, we will use the fact that $A$ and $B$ are sets. The first thing we must prove is: +As mentioned in section \S\ref{sec:equiv}. These maps are not in general inverses +of each other. In stead, we will use the fact that $A$ and $B$ are sets. The first thing we must prove is: % \begin{align*} \var{fromIso} \comp \var{toIso} ≡ \identity_{\isEquiv\ f} @@ -803,13 +824,13 @@ For the other direction: \var{toIso} \comp \var{fromIso} ≡ \identity_{\Isomorphism\ f} \end{align*} % -We will show that $\Isomorphism\ f$ is also a mere proposition. To this -end, let $X\;Y \tp \Isomorphism\ f$ be given. Name the maps $x\;y \tp B -→ A$ respectively. Now, the proof that $X$ and $Y$ are the same is a pair of -paths: $p \tp x ≡ y$ and $\Path\ (\lambda\; i → -\var{AreInverses}\ f\ (p\ i))\ \mathcal{X}\ \mathcal{Y}$ where $\mathcal{X}$ -and $\mathcal{Y}$ denotes the witnesses that $x$ (respectively $y$) is an -inverse to $f$. The path $p$ is inhabited by: +We will show that $\Isomorphism\ f$ is also a mere proposition. To +this end, let $X, Y \tp \Isomorphism\ f$ be given. Name the maps $x, y +\tp B → A$ respectively. Now, the proof that $X$ and $Y$ are the same +is a pair of paths: $p \tp x ≡ y$ and $\Path\ (\lambda\; i → +\var{AreInverses}\ f\ (p\ i))\ \mathcal{X}\ \mathcal{Y}$ where +$\mathcal{X}$ and $\mathcal{Y}$ denotes the witnesses that $x$ +(respectively $y$) is an inverse to $f$. The path $p$ is inhabited by: % \begin{align*} x @@ -823,11 +844,11 @@ inverse to $f$. The path $p$ is inhabited by: \end{align*} % For the other (dependent) path we can prove that being-an-inverse-of is a -proposition and then use $\lemPropF$. So we prove the generalization: +proposition and then use $\lemPropF$. So we prove the generalization: % \begin{align} -\label{eq:propAreInversesGen} -∏_{g \tp B → A} \isProp\ (\var{AreInverses}\ f\ g) + \label{eq:propAreInversesGen} + ∏_{g \tp B → A} \isProp\ (\var{AreInverses}\ f\ g) \end{align} % But $\var{AreInverses}\ f\ g$ is a pair of equations on arrows, so we use @@ -835,7 +856,7 @@ $\propSig$ and the fact that both $A$ and $B$ are sets to close this proof. %% \subsection{Category of categories} -%% Note that this category does in fact not exist. In stead I provide +%% Note that this category does in fact not exist. In stead I provide %% the definition of the ``raw'' category as well as some of the laws. %% Furthermore I provide some helpful lemmas about this raw category. @@ -843,65 +864,67 @@ $\propSig$ and the fact that both $A$ and $B$ are sets to close this proof. %% such a category. %% These lemmas can be used to provide the actual exponential object -%% in a context where we have a witness to this being a category. This +%% in a context where we have a witness to this being a category. This %% is useful if this library is later extended to talk about higher %% categories. \section{Products} \label{sec:products} In the following a technique for using categories to prove properties will be -demonstrated. The goal in this section is to show that products are +demonstrated. The goal in this section is to show that products are propositions: % $$ ∏_{\bC \tp \Category} ∏_{A\;B \tp \Object} \isProp\ (\var{Product}\ \bC\ A\ B) $$ % -Where $\var{Product}\ \bC\ A\ B$ denotes the type of products of objects $A$ -and $B$ in the category $\bC$. I do this by constructing a category whose -terminal objects are equivalent to products in $\bC$, and since terminal objects -are propositional in a proper category and equivalences preserve homotopy level, -then we know that products also are propositions. But before we get to that, -we recall the definition of products. +Where $\var{Product}\ \bC\ A\ B$ denotes the type of products of +objects $A$ and $B$ in the category $\bC$. I do this by constructing a +category whose terminal objects are equivalent to products in $\bC$, +and since terminal objects are propositional in a proper category and +equivalences preserve homotopy level, then we know that products are +also propositions. But before we get to that, we recall the definition +of products. \subsection{Definition of products} -Given a category $\bC$ and two objects $A$ and $B$ in $\bC$ we define the -product (object) of $A$ and $B$ to be an object $A \x B$ in $\bC$ and two arrows -$\pi_1 \tp A \x B → A$ and $\pi_2 \tp A \x B → B$ called the projections of -the product. The projections must satisfy the following property: +Given a category $\bC$ and two objects $A$ and $B$ in $\bC$ we say +that a product is triple consisting of an object and a pair of arrows. +The object is denoted with $A × B$ in $\bC$ and is also referred to as +the product (object) of $A$ and $B$. The arrows will be named $\pi_1 +\tp A \x B → A$ and $\pi_2 \tp A \x B → B$ also called the projections +of the product. The projections must satisfy the following property: For all $X \tp Object$, $f \tp \Arrow\ X\ A$ and $g \tp \Arrow\ X\ B$ we have that there exists a unique arrow $\pi \tp \Arrow\ X\ (A \x B)$ satisfying % \begin{align} -\label{eq:umpProduct} -%% ∏_{X \tp Object} ∏_{f \tp \Arrow\ X\ A} ∏_{g \tp \Arrow\ X\ B}\\ -%% \uexists_{f \x g \tp \Arrow\ X\ (A \x B)} -\pi_1 \lll \pi ≡ f \x \pi_2 \lll \pi ≡ g + \label{eq:umpProduct} + %% ∏_{X \tp Object} ∏_{f \tp \Arrow\ X\ A} ∏_{g \tp \Arrow\ X\ B}\\ + %% \uexists_{f \x g \tp \Arrow\ X\ (A \x B)} + \pi_1 \lll \pi ≡ f \x \pi_{2} \lll \pi ≡ g \end{align} % -$\pi$ is called the product (arrow) of $f$ and $g$. - +The arrow $\pi$ is called the product (arrow) of $f$ and $g$. +% \subsection{Span category} -Given a base category $\bC$ and two objects in this category $\pairA$ and -$\pairB$ we can construct the \nomenindex{span category}: - -The type of objects in this category will be an object in the underlying +Given a base category $\bC$ and two objects in this category $\pairA$ +and $\pairB$ we construct the \nomenindex{span category}. The type of +objects in this category shall be an object in the underlying category, $X$, and two arrows (also from the underlying category) $\Arrow\ X\ \pairA$ and $\Arrow\ X\ \pairB$. \newcommand\pairf{\ensuremath{f}} \newcommand\pairFst{\mathcal{\pi_1}} -\newcommand\pairSnd{\mathcal{\pi_2}} +\newcommand\pairSnd{\mathcal{\pi_{2}}} -An arrow between objects $A ,\ a_0 ,\ a_1$ and $B ,\ b_0 ,\ b_1$ in this +An arrow between objects $A ,\ a_{\pairA} ,\ a_{\pairB}$ and $B ,\ b_{\pairA} ,\ b_{\pairB}$ in this category will consist of an arrow from the underlying category $\pairf \tp \Arrow\ A\ B$ satisfying: % \begin{align} -\label{eq:pairArrowLaw} -b_0 \lll f ≡ a_0 \x -b_1 \lll f ≡ a_1 + \label{eq:pairArrowLaw} + b_{\pairA} \lll f ≡ a_{\pairA} \x + b_{\pairB} \lll f ≡ a_{\pairB} \end{align} The identity morphism is the identity morphism from the underlying category. @@ -913,27 +936,27 @@ choose $g \lll f$ and we must now verify that it satisfies \ref{eq:pairArrowLaw}: % \begin{align*} - c_0 \lll (f \lll g) + c_{\pairA} \lll (f \lll g) & ≡ - (c_0 \lll f) \lll g + (c_{\pairA} \lll f) \lll g && \text{Associativity} \\ & ≡ - b_0 \lll g + b_{\pairA} \lll g && \text{$f$ satisfies \ref{eq:pairArrowLaw}} \\ & ≡ - a_0 + a_{\pairA} && \text{$g$ satisfies \ref{eq:pairArrowLaw}} \\ \end{align*} % -Now we must verify the category-laws. For all the laws we will follow the +Now we must verify the category-laws. For all the laws we will follow the pattern of using the law from the underlying category, and that the type of -arrows form a set. For instance, to prove associativity we must prove that +arrows form a set. For instance, to prove associativity we must prove that % \begin{align} -\label{eq:productAssoc} -\overline{h} \lll (\overline{g} \lll \overline{f}) -≡ -(\overline{h} \lll \overline{g}) \lll \overline{f} + \label{eq:productAssoc} + \overline{h} \lll (\overline{g} \lll \overline{f}) + ≡ + (\overline{h} \lll \overline{g}) \lll \overline{f} \end{align} % Here $\lll$ refers to the `embellished' composition and $\overline{f}$, @@ -942,48 +965,51 @@ underlying category ($f$, $g$ and $h$) and a pair of witnesses to \ref{eq:pairArrowLaw}. %% Luckily those winesses are paths in the hom-set of the %% underlying category which is a set, so these are mere propositions. -The proof obligations is consists of two things. The first one is: +The proof obligations consists of two things. The first one is: % \begin{align} -\label{eq:productAssocUnderlying} -h \lll (g \lll f) -≡ -(h \lll g) \lll f + \label{eq:productAssocUnderlying} + h \lll (g \lll f) + ≡ + (h \lll g) \lll f \end{align} % And the other proof obligation is that the witness to \ref{eq:pairArrowLaw} for the left-hand-side and the right-hand-side are the same. -The proof of the first goal comes directly from the underlying category. The -type of the second goal is very complicated. I will not write it out in full -here, but it suffices to show the type of the path-space. Note that the arrows -in \ref{eq:productAssoc} are arrows from $\mathcal{A} = (A , a_{\pairA} , -a_{\pairB})$ to $\mathcal{D} = (D , d_{\pairA} , d_{\pairB})$ where -$a_{\pairA}$, $a_{\pairB}$, $d_{\pairA}$ and $d_{\pairB}$ are arrows in the -underlying category. Given that $p$ is the chosen proof of +The proof of the first goal comes directly from the underlying +category. The type of the second goal is very complicated. I will not +write it out in full here, but for the purpose of the present +exposition it will suffices to show the type of the path-space. Note +that the arrows in \ref{eq:productAssoc} are arrows between objects on +the form $\wideoverbar{A} = (A , a_{\pairA} , a_{\pairB})$ to +$\wideoverbar{D} = (D , d_{\pairA} , d_{\pairB})$ where $a_{\pairA}$, +$a_{\pairB}$, $d_{\pairA}$ and $d_{\pairB}$ are arrows in the +underlying category. Given that $p$ is the chosen proof of \ref{eq:productAssocUnderlying} we then have that the witness to \ref{eq:pairArrowLaw} vary over the type: % \begin{align} -\label{eq:productPath} -λ \; i → d_{\pairA} \lll p\ i ≡ 2 a_{\pairA} × d_{\pairB} \lll p\ i ≡ a_{\pairB} + \label{eq:productPath} + λ \; i → d_{\pairA} \lll p\ i ≡ a_{\pairA} × d_{\pairB} \lll p\ i ≡ a_{\pairB} \end{align} % And these paths are in the type of the hom-set of the underlying category, so -they are mere propositions. We cannot apply the fact that arrows in $\bC$ are +they are mere propositions. We cannot apply the fact that arrows in $\bC$ are sets directly, however, since $\isSet$ only talks about non-dependent paths, in stead we generalize \ref{eq:productPath} to: % \begin{align} -\label{eq:productEqPrinc} -∏_{f \tp \Arrow\ X\ Y} \isProp\ \left( y_{\pairA} \lll f ≡ x_{\pairA} × y_{\pairB} \lll f ≡ x_{\pairB} \right) + \label{eq:productEqPrinc} + ∏_{f \tp \Arrow\ X\ Y} \isProp\ \left( y_{\pairA} \lll f ≡ x_{\pairA} × y_{\pairB} \lll f ≡ x_{\pairB} \right) \end{align} % -For all objects $X , x_{\pairA} , x_{\pairB}$ and $Y , y_{\pairA} , y_{\pairB}$, -but this follows from pairs preserving homotopical structure and arrows in the -underlying category being sets. This gives us an equality principle for arrows -in this category that says that to prove two arrows $f, f_0, f_1$ and $g, g_0, -g_1$ equal it suffices to give a proof that $f$ and $g$ are equal. +For all objects $X , x_{\pairA} , x_{\pairB}$ and $Y , y_{\pairA} , +y_{\pairB}$, but this follows from the fact that $∏$ and $∑$ preserve +homotopical structure. This gives us an equality principle for arrows +in this category that says that to prove two arrows $f, f_0, f_1$ and +$g, g_0, g_1$ equal it suffices to give a proof that $f$ and $g$ are +equal. %% % %% $$ %% ∏_{(f, f_0, f_1)\; (g,g_0,g_1) \tp \Arrow\ X\ Y} f ≡ g \to (f, f_0, f_1) ≡ (g,g_0,g_1) @@ -995,22 +1021,23 @@ And thus we have proven \ref{eq:productAssoc} simply with Now we must prove that arrows form a set: % $$ -\isSet\ (\Arrow\ \mathcal{X}\ \mathcal{Y}) +\isSet\ (\Arrow\ \wideoverbar{X}\ \wideoverbar{Y}) $$ % -Since pairs preserve homotopical structure this reduces to: +Since pairs preserve homotopical structure this reduces to the two +obligations: % $$ -\isSet\ (\Arrow_{\bC}\ X\ Y) +\isSet\ (\bC.\Arrow\ X\ Y) $$ % -Which holds. And +Which holds. And % $$ ∏_{f \tp \Arrow\ X\ Y} \isSet\ \left( y_{\pairA} \lll f ≡ x_{\pairA} - × y_{\pairB} \lll f ≡ x_{\pairB} - \right) +× y_{\pairB} \lll f ≡ x_{\pairB} +\right) $$ % This we get from \ref{eq:productEqPrinc} and the fact that homotopical structure @@ -1024,7 +1051,7 @@ That is, for any two objects $\mathcal{X} = (X, x_{\mathcal{A}} , x_{\mathcal{B} and $\mathcal{Y} = Y, y_{\mathcal{A}}, y_{\mathcal{B}}$ I will show: % \begin{align} -(\mathcal{X} ≡ \mathcal{Y}) \cong (\mathcal{X} ≊ \mathcal{Y}) + (\mathcal{X} ≡ \mathcal{Y}) \cong (\mathcal{X} ≊ \mathcal{Y}) \end{align} I do this by showing that the following sequence of types are isomorphic. @@ -1032,32 +1059,32 @@ I do this by showing that the following sequence of types are isomorphic. The first type is: % \begin{align} -\label{eq:univ-0} -(X , x_{\mathcal{A}} , x_{\mathcal{B}}) ≡ (Y , y_{\mathcal{A}} , y_{\mathcal{B}}) + \label{eq:univ-0} + (X , x_{\mathcal{A}} , x_{\mathcal{B}}) ≡ (Y , y_{\mathcal{A}} , y_{\mathcal{B}}) \end{align} % The next types will be the triple: % \begin{align} -\label{eq:univ-1} -\begin{split} -p \tp & X ≡ Y \\ -& \Path\ (λ \; i → \Arrow\ (p\ i)\ \mathcal{A})\ x_{\mathcal{A}}\ y_{\mathcal{A}} \\ -& \Path\ (λ \; i → \Arrow\ (p\ i)\ \mathcal{B})\ x_{\mathcal{B}}\ y_{\mathcal{B}} -\end{split} -%% \end{split} + \label{eq:univ-1} + \begin{split} + p \tp & X ≡ Y \\ + & \Path\ (λ \; i → \Arrow\ (p\ i)\ \mathcal{A})\ x_{\mathcal{A}}\ y_{\mathcal{A}} \\ + & \Path\ (λ \; i → \Arrow\ (p\ i)\ \mathcal{B})\ x_{\mathcal{B}}\ y_{\mathcal{B}} + \end{split} + %% \end{split} \end{align} The next type is very similar, but in stead of a path we will have an isomorphism, and create a path from this: % \begin{align} -\label{eq:univ-2} -\begin{split} -\var{iso} \tp & X ≊ Y \\ -& \Path\ (λ \; i → \Arrow\ (\widetilde{p}\ i)\ \mathcal{A})\ x_{\mathcal{A}}\ y_{\mathcal{A}} \\ -& \Path\ (λ \; i → \Arrow\ (\widetilde{p}\ i)\ \mathcal{B})\ x_{\mathcal{B}}\ y_{\mathcal{B}} -\end{split} + \label{eq:univ-2} + \begin{split} + \var{iso} \tp & X ≊ Y \\ + & \Path\ (λ \; i → \Arrow\ (\widetilde{p}\ i)\ \mathcal{A})\ x_{\mathcal{A}}\ y_{\mathcal{A}} \\ + & \Path\ (λ \; i → \Arrow\ (\widetilde{p}\ i)\ \mathcal{B})\ x_{\mathcal{B}}\ y_{\mathcal{B}} + \end{split} \end{align} % Where $\widetilde{p} ≜ \isoToId\ \var{iso} \tp X ≡ Y$. @@ -1065,20 +1092,28 @@ Where $\widetilde{p} ≜ \isoToId\ \var{iso} \tp X ≡ Y$. Finally we have the type: % \begin{align} -\label{eq:univ-3} -(X , x_{\mathcal{A}} , x_{\mathcal{B}}) ≊ (Y , y_{\mathcal{A}} , y_{\mathcal{B}}) + \label{eq:univ-3} + (X , x_{\mathcal{A}} , x_{\mathcal{B}}) ≊ (Y , y_{\mathcal{A}} , y_{\mathcal{B}}) \end{align} +% +So the proof is a chain of isomorphisms between the types +\ref{eq:univ-0}, \ref{eq:univ-1}, \ref{eq:univ-2} and +\ref{eq:univ-3}. I will highlight the most interesting bits of this +proof. For the full proof see the implementation in the module: +% +\begin{center} + \sourcelink{Cat.Categories.Span} +\end{center} \emph{Proposition} \ref{eq:univ-0} is isomorphic to \ref{eq:univ-1}: This is just an application of the fact that a path between two pairs $a_0, a_1$ and -$b_0, b_1$ corresponds to a pair of paths between $a_0,b_0$ and $a_1,b_1$ (check -the implementation for the details). +$b_0, b_1$ corresponds to a pair of paths between $a_0,b_0$ and $a_1,b_1$. \emph{Proposition} \ref{eq:univ-1} is isomorphic to \ref{eq:univ-2}: This proof of this has been omitted but can be found in the module: % \begin{center}% -\sourcelink{Cat.Categories.Span} + \sourcelink{Cat.Categories.Span} \end{center} % \emph{Proposition} \ref{eq:univ-2} is isomorphic to \ref{eq:univ-3}: For this I @@ -1090,54 +1125,56 @@ will show two corollaries of \ref{eq:coeCod}: For an isomorphism $(\iota, results % \begin{align} -\label{eq:domain-twist-0} -f & ≡ g \lll \iota \\ -\label{eq:domain-twist-1} -g & ≡ f \lll \inv{\iota} + \label{eq:domain-twist-0} + f & ≡ g \lll \iota \\ + \label{eq:domain-twist-1} + g & ≡ f \lll \inv{\iota} \end{align} % The proof is omitted but can be found in the module: \begin{center} -\sourcelink{Cat.Category} + \sourcelink{Cat.Category} \end{center} Now we can prove the equivalence in the following way: Given $(f, \inv{f}, \var{inv}_f) \tp X \cong Y$ and two heterogeneous paths % \begin{align*} -p_{\mathcal{A}} & \tp \Path\ (\lambda\; i → p_{\var{dom}}\ i)\ x_{\mathcal{A}}\ y_{\mathcal{A}}\\ -% -q_{\mathcal{B}} & \tp \Path\ (\lambda\; i → p_{\var{dom}}\ i)\ x_{\mathcal{B}}\ y_{\mathcal{B}} + p_{\mathcal{A}} & \tp \Path\ (\lambda\; i → p_{\var{dom}}\ i)\ x_{\mathcal{A}}\ y_{\mathcal{A}}\\ + % + q_{\mathcal{B}} & \tp \Path\ (\lambda\; i → p_{\var{dom}}\ i)\ x_{\mathcal{B}}\ y_{\mathcal{B}} \end{align*} % -all as in \ref{eq:univ-2}. I use $p_{\var{dom}}$ here again to mean the path -induced by the isomorphism $f, \inv{f}$. I must now construct an isomorphism -$(X, x_{\mathcal{A}}, x_{\mathcal{B}}) ≊ (Y, y_{\mathcal{A}}, y_{\mathcal{B}})$ -as in \ref{eq:univ-3}. That is, an isomorphism in the present category. I remind -the reader that such a gadget is a triple. The first component shall be: +all as in \ref{eq:univ-2}. I use $p_{\var{dom}}$ here again to mean +the path induced by the isomorphism $(f, \inv{f}, \var{inv}_f)$. We +must now construct an isomorphism $(X, x_{\mathcal{A}}, +x_{\mathcal{B}}) ≊ (Y, y_{\mathcal{A}}, y_{\mathcal{B}})$ as in +\ref{eq:univ-3}. That is, an isomorphism in the present category. I +remind the reader that such a gadget is a triple. The first component +shall be: % \begin{align} -f \tp \Arrow\ X\ Y + f \tp \Arrow\ X\ Y \end{align} % To show that this choice fits the bill I must now verify that it satisfies \ref{eq:pairArrowLaw}, which in this case becomes: % \begin{align} -(y_{\mathcal{A}} \lll f ≡ x_{\mathcal{A}}) × (y_{\mathcal{B}} \lll f ≡ x_{\mathcal{B}}) + (y_{\mathcal{A}} \lll f ≡ x_{\mathcal{A}}) × (y_{\mathcal{B}} \lll f ≡ x_{\mathcal{B}}) \end{align} % Which, since $f$ is an isomorphism and $p_{\mathcal{A}}$ (resp.\ $p_{\mathcal{B}}$) is a path varying according to a path constructed from this isomorphism, this is exactly what \ref{eq:domain-twist-0} gives us. % -The other direction is quite analogous. We choose $\inv{f}$ as the morphism and +The other direction is quite analogous. We choose $\inv{f}$ as the morphism and prove that it satisfies \ref{eq:pairArrowLaw} with \ref{eq:domain-twist-1}. -We must now show that this choice of arrows indeed form an isomorphism. Our -equality principle for arrows in this category (\ref{eq:productEqPrinc}) gives -us that it suffices to show that $f$ and $\inv{f}$, this is exactly -$\var{inv}_f$. +We must now show that this choice of arrows indeed form an +isomorphism. Our equality principle for arrows in this category +(\ref{eq:productEqPrinc}) gives us that it suffices to show that $f$ +and $\inv{f}$ are inverses, but this is of course just $\var{inv}_f$. This concludes the first direction of the isomorphism that we are constructing. For the other direction we are given the isomorphism: @@ -1161,70 +1198,70 @@ $$ This gives rise to the following paths: % \begin{align} -\begin{split} -\widetilde{p} & \tp X ≡ Y \\ -\widetilde{p}_{\mathcal{A}} & \tp \Arrow\ X\ \mathcal{A} ≡ \Arrow\ Y\ \mathcal{A} \\ -\widetilde{p}_{\mathcal{B}} & \tp \Arrow\ X\ \mathcal{B} ≡ \Arrow\ Y\ \mathcal{B} -\end{split} + \begin{split} + \widetilde{p} & \tp X ≡ Y \\ + \widetilde{p}_{\mathcal{A}} & \tp \Arrow\ X\ \mathcal{A} ≡ \Arrow\ Y\ \mathcal{A} \\ + \widetilde{p}_{\mathcal{B}} & \tp \Arrow\ X\ \mathcal{B} ≡ \Arrow\ Y\ \mathcal{B} + \end{split} \end{align} % It then remains to construct the two paths: % \begin{align} -\begin{split} -\label{eq:product-paths} -& \Path\ (λ \; i → \widetilde{p}_{\mathcal{A}}\ i)\ x_{\mathcal{A}}\ y_{\mathcal{A}}\\ -& \Path\ (λ \; i → \widetilde{p}_{\mathcal{B}}\ i)\ x_{\mathcal{B}}\ y_{\mathcal{B}} -\end{split} + \begin{split} + \label{eq:product-paths} + & \Path\ (λ \; i → \widetilde{p}_{\mathcal{A}}\ i)\ x_{\mathcal{A}}\ y_{\mathcal{A}}\\ + & \Path\ (λ \; i → \widetilde{p}_{\mathcal{B}}\ i)\ x_{\mathcal{B}}\ y_{\mathcal{B}} + \end{split} \end{align} % This is achieved with the following lemma: % \begin{align} -∏_{a \tp A} ∏_{b \tp B} ∏_{q \tp A ≡ B} \var{coe}\ q\ a ≡ b → -\Path\ (λ \; i → q\ i)\ a\ b + ∏_{a \tp A} ∏_{b \tp B} ∏_{q \tp A ≡ B} \var{coe}\ q\ a ≡ b → + \Path\ (λ \; i → q\ i)\ a\ b \end{align} % -Which is used without proof. See the implementation for the details. +Which is used without proof. See the implementation for the details. \ref{eq:product-paths} is then proven with the propositions: % \begin{align} -\begin{split} -%% \label{eq:product-paths} -\var{coe}\ \widetilde{p}_{\mathcal{A}}\ x_{\mathcal{A}} ≡ y_{\mathcal{A}}\\ -\var{coe}\ \widetilde{p}_{\mathcal{B}}\ x_{\mathcal{B}} ≡ y_{\mathcal{B}} -\end{split} + \begin{split} + %% \label{eq:product-paths} + \var{coe}\ \widetilde{p}_{\mathcal{A}}\ x_{\mathcal{A}} ≡ y_{\mathcal{A}}\\ + \var{coe}\ \widetilde{p}_{\mathcal{B}}\ x_{\mathcal{B}} ≡ y_{\mathcal{B}} + \end{split} \end{align} % The proof of the first one is: % \begin{align*} \var{coe}\ \widetilde{p}_{\mathcal{A}}\ x_{\mathcal{A}} - & ≡ x_{\mathcal{A}} \lll \fst\ \inv{f} && \text{\ref{eq:coeDom} and the isomorphism $f, \inv{f}$} \\ + & ≡ x_{\mathcal{A}} \lll \fst\ \inv{f} && \text{\ref{eq:coeDom} and the isomorphism $(f, \inv{f}, \var{inv}_{f})$} \\ & ≡ y_{\mathcal{A}} && \text{\ref{eq:pairArrowLaw} for $\inv{f}$} \end{align*} % -We have now constructed the maps between \ref{eq:univ-0} and \ref{eq:univ-1}. It -remains to show that they are inverses of each other. To cut a long story short, -the proof uses the fact that isomorphism-of is propositional and that arrows (in -both categories) are sets. The reader is referred to the implementation for the +We have now constructed the maps between \ref{eq:univ-0} and +\ref{eq:univ-1}. It remains to show that they are inverses of each +other. To cut a long story short, the proof uses the fact that +isomorphism-of is a proposition and that arrows (in both categories) +are sets. The reader is referred to the implementation for the full gory details. % \subsection{Products are propositions} % Now that we have constructed the span category\index{span category} I will demonstrate how to use this to prove that products are -propositions. On the face of it this may seem surprising. Products -look like they are a structure on categories. After all it consist of -a select element and two arrows given some two objects. If formulated -in set theory this would be the case but in the present setting -univalence of categories give us that products are properties. I will -show this by showing that terminal objects in the span category are -equivalent to products: +propositions. On the face of it this may seem surprising. Products +look like they are a structure on categories. After all it consist of +a select object and two arrows. If formulated in set theory this +would be the case but in the present setting univalence of categories +give us that products are properties. I will show this by showing +that terminal objects in the span category are equivalent to products: % \begin{align} -\var{Terminal} ≃ \var{Product}\ ℂ\ \mathcal{A}\ \mathcal{B} + \var{Terminal} ≃ \var{Product}\ ℂ\ \mathcal{A}\ \mathcal{B} \end{align} % And as always we do this by constructing an isomorphism: @@ -1237,49 +1274,50 @@ indeed a product. That is, for an object $Y$ and two arrows $y_𝒜 \tp \Arrow\ Y\ X$ satisfying: % \begin{align} -\label{eq:pairCondRev} -%% \begin{split} + \label{eq:pairCondRev} + %% \begin{split} ( x_𝒜 \lll f ≡ y_𝒜 ) \x ( x_ℬ \lll f ≡ y_ℬ ) -%% \end{split} + %% \end{split} \end{align} % -Since $X, x_𝒜, x_ℬ$ is a terminal object there is a \emph{unique} arrow from -this object to any other object, so also $Y, y_𝒜, y_ℬ$ in particular (which is -also an object in the span category). The arrow we will play the role of $f$ and -it immediately satisfies \ref{eq:pairCondRev}. Any other arrow satisfying these +Since $X, x_𝒜, x_ℬ$ is a terminal object there is a \emph{unique} +arrow from this object to any other object, so in particular also $Y, +y_𝒜, y_ℬ$. The arrow we will play the role of $f$ and it immediately +satisfies \ref{eq:pairCondRev}. Any other arrow satisfying these conditions will be equal since $f$ is unique. -For the other direction we are now given a product $X, x_𝒜, x_ℬ$. Again this -will be the terminal object. So now it remains that for any other object there -is a unique arrow from that object into $X, x_𝒜, x_ℬ$. Let $Y, y_𝒜, y_ℬ$ be -another object. As the arrow $\Arrow\ Y\ X$ we choose the product-arrow $y_𝒜 \x -y_ℬ$. Since this is a product-arrow it satisfies \ref{eq:pairCondRev}. Let us -name the witness to this $\phi_{y_𝒜 \x y_ℬ}$. So we have picked as our center of -contraction $y_𝒜 \x y_ℬ , \phi_{y_𝒜 \x y_ℬ}$ we must now show that it is -contractible. So let $f \tp \Arrow\ X\ Y$ and $\phi_f$ be given (here $\phi_f$ -is the proof that $f$ satisfies \ref{eq:pairCondRev}). The proof will be a pair -of proofs: +For the other direction we are now given a product $X, x_𝒜, x_ℬ$. +Again this will be the terminal object. So now it remains that for +any other object there is a unique arrow from that object into $X, +x_𝒜, x_ℬ$. Let $Y, y_𝒜, y_ℬ$ be another object. As the arrow +$\Arrow\ Y\ X$ we choose the product-arrow $y_𝒜 \x y_ℬ$. Since this +is a product-arrow it satisfies \ref{eq:pairCondRev}. Let us name the +witness to this $\phi_{y_𝒜 \x y_ℬ}$. So we have picked as our center +of contraction $y_𝒜 \x y_ℬ , \phi_{y_𝒜 \x y_ℬ}$ we must now show that +it is contractible. So let $f \tp \Arrow\ X\ Y$ and $\phi_f$ be given +(here $\phi_f$ is the proof that $f$ satisfies \ref{eq:pairCondRev}). +The proof will be a pair of proofs: % \begin{alignat}{3} p \tp & \Path\ (\lambda\; i → \Arrow\ X\ Y)\quad - && f\quad && y_𝒜 \x y_ℬ \\ + && f\quad && y_𝒜 \x y_ℬ \\ & \Path\ (\lambda\; i → \Phi\ (p\ i))\quad - && \phi_f\quad && \phi_{y_𝒜 \x y_ℬ} + && \phi_f\quad && \phi_{y_𝒜 \x y_ℬ} \end{alignat} % Here $\Phi$ is given as: $$ ∏_{f \tp \Arrow\ Y\ X} - ( x_𝒜 \lll f ≡ y_𝒜 ) - × - ( x_ℬ \lll f ≡ y_ℬ ) +( x_𝒜 \lll f ≡ y_𝒜 ) +× +( x_ℬ \lll f ≡ y_ℬ ) $$ % -$p$ follows from the universal property of $y_𝒜 \x y_ℬ$. For the latter we will -again use the same trick we did in \ref{eq:propAreInversesGen} and prove this -more general result: +We can construct $p$ from the universal property of $y_𝒜 \x y_ℬ$. For +the latter we use the same trick we did in \ref{eq:propAreInversesGen} +and prove this more general result: % $$ ∏_{f \tp \Arrow\ Y\ X} \isProp\ ( @@ -1289,30 +1327,31 @@ $$ ) $$ % -Which follows from arrows being sets and pairs preserving such. Thus we can +Which follows from arrows being sets and pairs preserving such. Thus we can close the final proof with an application of $\lemPropF$. -This concludes the proof $\var{Terminal} ≃ -\var{Product}\ ℂ\ \mathcal{A}\ \mathcal{B}$ and since we have that equivalences -preserve homotopic levels along with \ref{eq:termProp} we get our final result. -That in any category: +This concludes the proof +$\var{Terminal} ≃ \var{Product}\ ℂ\ \mathcal{A}\ \mathcal{B}$ +and since we have that equivalences preserve homotopic levels along +with \ref{eq:termProp} we get our final result. That is, in any +category $\bC$ we have: % \begin{align} -∏_{A, B \tp \Object} \isProp\ (\var{Product}\ \bC\ A\ B) + ∏_{A, B \tp \Object} \isProp\ (\var{Product}\ \bC\ A\ B) \end{align} % \section{Functors and natural transformations} -For the sake of completeness I will mention the definition of functors -and natural transformations. Please refer to the implementation for -the full details. +For the sake of completeness I will briefly mention the definition of +functors and natural transformations. Please refer to the +implementation for the full details. % \subsection{Functors} Given two categories $\bC$ and $\bD$ a functor consists of the following data: % \begin{align*} - \omapF & \tp ℂ.\Object → 𝔻.\Object \\ - \fmap & \tp ℂ.\Arrow\ A\ B → 𝔻.\Arrow\ (\omapF\ A)\ (\omapF\ B) + \omapF & \tp ℂ.\Object → 𝔻.\Object \\ + \fmap & \tp ℂ.\Arrow\ A\ B → 𝔻.\Arrow\ (\omapF\ A)\ (\omapF\ B) \end{align*} % And the following laws: @@ -1327,16 +1366,17 @@ The implementation can be found here: \sourcelink{Cat.Category.Functor} \end{center} \subsection{Natural Transformation} -Given two functors between categories $\bC$ and $\bD$. Name them -$\FunF$ and $\FunG$. A natural transformation is a family of arrows: +\label{sec:nat-trans} +Given two functors between categories $\bC$ and $\bD$. Name them +$\FunF$ and $\FunG$. A natural transformation is a family of arrows: % \begin{align*} ∏_{C \tp ℂ.\Object} \bD.\Arrow\ (\omapF\ C)\ (\omapG\ C) \end{align*} % -This family of arrows can be seen as the data. If $\theta$ is a +This family of arrows can be seen as the data. If $\theta$ is a natural transformation $\theta\ C$ will be called the component (of -$\theta$) at $C$. The laws of this family of morphism is the +$\theta$) at $C$. The laws of this family of morphism is the naturality condition: % \begin{align*} @@ -1352,20 +1392,20 @@ The implementation can be found here: \section{Monads} \label{sec:monads} -In this section I present two formulations of monads. The two representations -are referred to as the monoidal- and Kleisli- representation respectively or -simply monoidal monads and Kleisli monads for short. We then show that the two -formulations are equivalent, which due to univalence gives us a path between the -two types. +In this section I present two formulations of monads. The two +representations are referred to as the monoidal- and Kleisli- +representation respectively or simply monoidal monads and Kleisli +monads. We then show that the two formulations are equivalent, which +due to univalence gives us a path between the two types. -Let a category $\bC$ be given. In the remainder of this sections all +Let a category $\bC$ be given. In the remainder of this sections all objects and arrows will implicitly refer to objects and arrows in this -category. I will also use the notation $\EndoR$ to refer to an -endofunctor on this category. Its map on objects will be denoted -$\omapR$ and its map on arrows will be denoted $\fmap$. Likewise I +category. I will also use the notation $\EndoR$ to refer to an +endofunctor on this category. Its map on objects will be denoted +$\omapR$ and its map on arrows will be denoted $\fmap$. Likewise I will use the notation $\pureNT$ to refer to a natural transformation and its component at a given (implicit) object will be denoted -$\pure$. +$\pure$. This is the same notation as in \S\ref{sec:nat-trans}. % \subsection{Monoidal formulation} The monoidal formulation of monads consists of the following data: @@ -1374,18 +1414,16 @@ The monoidal formulation of monads consists of the following data: \label{eq:monad-monoidal-data} \begin{split} \EndoR & \tp \Functor\ ℂ\ \bC \\ - \pureNT & \tp \NT{\EndoR^0}{\EndoR} \\ - \joinNT & \tp \NT{\EndoR^2}{\EndoR} + \pureNT & \tp \NT{\widehat{\identity}}{\EndoR} \\ + \joinNT & \tp \NT{(\EndoR \oplus \EndoR)}{\EndoR} \end{split} \end{align} % -Here $\NTsym$ denotes natural transformations, the super-script in $\EndoR^2$ -Denotes the composition of $\EndoR$ with itself. By the same token $\EndoR^0$ is -a curious way of denoting the identity functor. This notation has been chosen -for didactic purposes. +Here $\NTsym$ denotes natural transformations and $\oplus$ means +functor composition. -Denote the arrow-map of $\EndoR$ as $\fmap$, then this data must satisfy the -following laws: +Note that $\fmap$ is $\EndoR$'s map on arrows. This data must satisfy +the following laws. % \begin{align} \label{eq:monad-monoidal-laws-0} @@ -1400,23 +1438,22 @@ following laws: % The implicit arguments to the arrows above have been left out and the objects they range over are universally quantified. - +% \subsection{Kleisli formulation} % The Kleisli-formulation consists of the following data: % \begin{align} -\begin{split} -\label{eq:monad-kleisli-data} -\omapR & \tp \Object → \Object \\ -\pure & \tp % ∏_{X \tp Object} - \Arrow\ X\ (\omapR\ X) \\ - \bind & \tp % ∏_{X\;Y \tp Object} → \Arrow\ X\ (\omapR\ Y) - \Arrow\ (\omapR\ X)\ (\omapR\ Y) -\end{split} + \begin{split} + \label{eq:monad-kleisli-data} + \omapR & \tp \Object → \Object \\ + \pure & \tp % ∏_{X \tp Object} + \Arrow\ X\ (\omapR\ X) \\ + \bind & \tp \Arrow\ X\ (\omapR\ Y) → \Arrow\ (\omapR\ X)\ (\omapR\ Y) + \end{split} \end{align} % -The objects $X$ and $Y$ are implicitly universally quantified. With this data we can construct the \nomenindex{Kleisli arrow}: +The objects $X$ and $Y$ are implicitly universally quantified. With this data we can construct the \nomenindex{Kleisli arrow}: % \begin{align*} \fish & \tp \Arrow\ A\ (\omapR\ B) @@ -1425,15 +1462,15 @@ The objects $X$ and $Y$ are implicitly universally quantified. With this data we f \fish g & ≜ f \rrr (\bind\ g) \end{align*} % -It is interesting to note here that this formulation does not talk about natural -transformations or other such constructs from category theory. All we have here -is a regular maps on objects and a pair of arrows. +It is interesting to note here that this formulation does mention +functors nor natural transformations. All we have here is a regular +map on objects and a pair of arrows. % This data must satisfy: % \begin{align} \label{eq:monad-kleisli-laws-0} -\bind\ \pure & ≡ \identity_{\EndoR\ X} \\ +\bind\ \pure & ≡ \identity_{\omapR\ X} \\ \label{eq:monad-kleisli-laws-1} \pure \fish f & ≡ f \\ \label{eq:monad-kleisli-laws-2} @@ -1443,15 +1480,16 @@ This data must satisfy: % Here likewise the arrows $f \tp \Arrow\ X\ (\omapR\ Y)$ and $g \tp \Arrow\ Y\ (\omapR\ Z)$ are universally quantified as well as the -objects they range over. +objects they range over. The third law is stated in terms of reverse +function composition to mirror the way in which it interacts with the +Kleisli arrow. % \subsection{Equivalence of formulations} % -The notation I have chosen here in the report -overloads e.g.\ $\pure$ to both refer to a natural transformation and an arrow. -This is of course not a coincidence as the arrow in the Kleisli formulation -shall correspond exactly to the map on arrows from the natural transformation -called $\pure$. +Both formulations mention a map called $\pure$. This is of course no +coincidence as that arrow in the Kleisli formulation shall correspond +exactly to the map on arrows for the natural transformation in the +monoidal formulation. In the monoidal formulation we can define $\bind$: % @@ -1471,14 +1509,14 @@ And likewise in the Kleisli formulation we can define $\join$: \end{align} % It now remains to show that this construction indeed gives rise to a -monad. This will be done in two steps. First we will assume that we +monad. This will be done in two steps. First we will assume that we have a monad in the monoidal form; $(\EndoR, \pure, \join)$ and then show that $(\omapR, \pure, \bind)$ is indeed a monad in the Kleisli -form. In the second part we will show the other direction. +form. In the second part we will show the other direction. \subsubsection{Monoidal to Kleisli} Let $(\EndoR, \pureNT, \joinNT)$ be given as in \ref{eq:monad-monoidal-data} -satisfying the laws \monoidallaws. For the data of the Kleisli +satisfying the laws \monoidallaws. For the data of the Kleisli formulation we pick: % \begin{align} @@ -1492,8 +1530,8 @@ formulation we pick: Again $\omapR$ is the object map of the endo-functor $\EndoR$, $\pure$ and $\join$ are the arrows from the natural transformations $\pureNT$ and $\joinNT$ respectively and $\fmap$ is the map on arrows of the -endofunctor $\EndoR$. It now just remains to verify the laws -\kleislilaws. For \ref{eq:monad-kleisli-laws-0}: +endofunctor $\EndoR$. It now just remains to verify the laws +\kleislilaws. For \ref{eq:monad-kleisli-laws-0}: % \begin{align*} \bind\ \pure & = @@ -1525,7 +1563,7 @@ For \ref{eq:monad-kleisli-laws-2}: \join \lll \join \lll (\fmap \comp \fmap)\ f \lll \fmap\ g && \text{$\join$ is a natural transformation} \\ & ≡ \join \lll \fmap\ \join \lll (\fmap \comp \fmap)\ f \lll \fmap\ g -&& \text{By \ref{eq:monad-monoidal-laws-0}} \\ & ≡ +&& \text{By \ref{eq:monad-monoidal-laws-0}} \\ & = \join \lll \fmap\ \join \lll \fmap\ (\fmap\ f) \lll \fmap\ g && \text{} \\ & ≡ \join \lll \fmap\ (\join \lll \fmap\ f \lll g) @@ -1544,7 +1582,7 @@ The construction can be found in the module: % \subsubsection{Kleisli to Monoidal} For the other direction we are given $(\omapR, \pure, \bind)$ as in -\ref{eq:monad-kleisli-data} satisfying the laws \kleislilaws. For the data of +\ref{eq:monad-kleisli-data} satisfying the laws \kleislilaws. For the data of the monoidal formulation we pick: % \begin{align} @@ -1557,9 +1595,10 @@ the monoidal formulation we pick: % We must now not only show the monad laws given for the monoidal formulation (\monoidallaws), we must also verify that $\EndoR$ is a -functor and that $\pure$ and $\join$ are natural transformations. I -will ommit this here. In stead we shall see how these two mappings are -indeed inverses. The full construction can be found in the module: +functor and that $\pure$ and $\join$ are natural transformations. I +will ommit this here. In stead we shall see how these two mappings +are indeed inverses. The full construction can be found in the +module: \begin{center} \mbox{\sourcelink{Cat.Category.Monad.Kleisli}} \end{center} @@ -1567,7 +1606,7 @@ indeed inverses. The full construction can be found in the module: \subsubsection{Equivalence} To prove that the two formulations are equivalent we must demonstrate that the two mappings sketched above are indeed inverses of each -other. To recap, these maps are: +other. To recap, these maps are: % \begin{align*} \toKleisli & \tp \var{Kleisli} → \var{Monoidal} \\ @@ -1575,10 +1614,10 @@ other. To recap, these maps are: → (\EndoR, \pure, \bind\ \identity) \end{align*} % -Where $\EndoR ≜ (\omapR, \bind\ (\pure \lll f))$. The proof that +Where $\EndoR ≜ (\omapR, \bind\ (\pure \lll f))$. The proof that this is indeed a functor is left implicit as well as the monad laws. Likewise the proof that $\pure$ and $\bind\ \identity$ are natural -transformations are left implicit. The inverse map will be: +transformations are left implicit. The inverse map will be: % \begin{align*} \toMonoidal & \tp \var{Monoidal} → \var{Kleisli} \\ @@ -1586,8 +1625,8 @@ transformations are left implicit. The inverse map will be: → (\omapR, \pure, \bind) \end{align*} % -Where $\bind\ f ≜ \join \lll \fmap\ f$. Again the monad laws are -left implicit. Now we must show: +Where $\bind\ f ≜ \join \lll \fmap\ f$. Again the monad laws are +left implicit. Now we must show: % \begin{align} \label{eq:monad-forwards} @@ -1597,15 +1636,15 @@ left implicit. Now we must show: \end{align} % For \ref{eq:monad-forwards} let $(\omapR, \pure, \bind)$ be a monad in -the Kleisli form. Since being-a-monad is a proposition\footnote{The - proof can be found in the implementation.} we get an -equality-principle for kleisli-monads that say that to equate two such -monads it suffices to equate their data-part. So it suffices to equate -the data-parts of the \ref{eq:monad-forwards}. Such a proof is a -triple equating the three projections of \ref{eq:monad-kleisli-data}. -The first two hold definitionally -- essentially one just wraps and -unwraps the morphism in a functor. For the last equation a little more -work is required: +the Kleisli form. Since being-a-monad is a proposition\footnote{The + proof was omitted here but can be found in the implementation.} we +get an equality-principle for kleisli-monads that say that to equate +two such monads it suffices to equate their data-part. So it suffices +to equate the data-parts of the \ref{eq:monad-forwards}. Such a proof +is a triple equating the three projections of +\ref{eq:monad-kleisli-data}. The first two hold definitionally -- +essentially one just wraps and unwraps the morphism in a functor. For +the last equation a little more work is required: % \begin{align*} \join \lll \fmap\ f & = @@ -1620,11 +1659,11 @@ work is required: \end{align*} % For the other direction (\ref{eq:monad-backwards}) we are given a -monad in the monoidal form; $(\EndoR, \pureNT, \joinNT)$. The various +monad in the monoidal form; $(\EndoR, \pureNT, \joinNT)$. The various equality-principles again give us that it is sufficient to equate the -data-part of the above. That is, we only need to verify that the +data-part of the above. That is, we only need to verify that the following pieces of data: $\omapR$, $\fmap$, $\pure$ and $\join$ get -mapped correctly. To see the full details check the implementation in +mapped correctly. To see the full details check the implementation in the module: % \begin{center} diff --git a/doc/introduction.tex b/doc/introduction.tex index d4effb8..476b62c 100644 --- a/doc/introduction.tex +++ b/doc/introduction.tex @@ -207,13 +207,13 @@ with \nomenindex{extensional sets} $(X, \sim)$. That is a type $X \tp \MCU$ and an equivalence relation $\sim\ \tp X \to X \to \MCU$ on that type. Under the setoid interpretation the equivalence relation serve as a sort of ``local'' propositional equality. Since the developer -gets to pick this relation it is not a\~priori a congruence +gets to pick this relation it is not a~priori a congruence relation. So this must be verified manually by the developer. Furthermore, functions between different setoids must be shown to be setoid homomorphism, that is; they preserve the relation. This approach has other drawbacks; it does not satisfy all -propositional equalities of type theory a priori. That is, the +propositional equalities of type theory a\~priori. That is, the developer must manually show that e.g.\ the relation is a congruence. Equational proofs $a \sim_{X} b$ are in some sense `local' to the extensional set $(X , \sim)$. To e.g.\ prove that $x ∼ y → f\ x ∼ From 392d656709d1f9dd782746f5b33725d605bf5b93 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frederik=20Hangh=C3=B8j=20Iversen?= Date: Tue, 29 May 2018 15:14:27 +0200 Subject: [PATCH 31/33] Move included graphics --- doc/assets/isomorphism.pdf | Bin 0 -> 327698 bytes doc/{ => assets}/isomorphism.png | Bin doc/chalmerstitle.sty | 2 +- 3 files changed, 1 insertion(+), 1 deletion(-) create mode 100644 doc/assets/isomorphism.pdf rename doc/{ => assets}/isomorphism.png (100%) diff --git a/doc/assets/isomorphism.pdf b/doc/assets/isomorphism.pdf new file mode 100644 index 0000000000000000000000000000000000000000..da44a39f66f61723185ff73ba76d7c4d9d11dee8 GIT binary patch literal 327698 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 z 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%0AP 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 Date: Tue, 29 May 2018 15:14:46 +0200 Subject: [PATCH 32/33] Add type-synonym --- src/Cat/Categories/Span.agda | 35 ++++++++++++++++------------------- 1 file changed, 16 insertions(+), 19 deletions(-) diff --git a/src/Cat/Categories/Span.agda b/src/Cat/Categories/Span.agda index 3573266..ddb2223 100644 --- a/src/Cat/Categories/Span.agda +++ b/src/Cat/Categories/Span.agda @@ -71,9 +71,20 @@ module _ {ℓa ℓb : Level} (ℂ : Category ℓa ℓb) open Σ 𝕐 renaming (fst to Y ; snd to y) open Σ y renaming (fst to ya ; snd to yb) open import Cat.Equivalence using (composeIso) renaming (_≅_ to _≅_) - step0 - : ((X , xa , xb) ≡ (Y , ya , yb)) - ≅ (Σ[ p ∈ (X ≡ Y) ] (PathP (λ i → ℂ.Arrow (p i) 𝒜) xa ya) × (PathP (λ i → ℂ.Arrow (p i) ℬ) xb yb)) + + -- The proof will be a sequence of isomorphisms between the + -- following 4 types: + T0 = ((X , xa , xb) ≡ (Y , ya , yb)) + T1 = (Σ[ p ∈ (X ≡ Y) ] (PathP (λ i → ℂ.Arrow (p i) 𝒜) xa ya) × (PathP (λ i → ℂ.Arrow (p i) ℬ) xb yb)) + T2 = Σ (X ℂ.≊ Y) (λ iso + → let p = ℂ.isoToId iso + in + ( PathP (λ i → ℂ.Arrow (p i) 𝒜) xa ya) + × PathP (λ i → ℂ.Arrow (p i) ℬ) xb yb + ) + T3 = ((X , xa , xb) ≊ (Y , ya , yb)) + + step0 : T0 ≅ T1 step0 = (λ p → cong fst p , cong-d (fst ∘ snd) p , cong-d (snd ∘ snd) p) -- , (λ x → λ i → fst x i , (fst (snd x) i) , (snd (snd x) i)) @@ -81,14 +92,7 @@ module _ {ℓa ℓb : Level} (ℂ : Category ℓa ℓb) , funExt (λ{ p → refl}) , funExt (λ{ (p , q , r) → refl}) - step1 - : (Σ[ p ∈ (X ≡ Y) ] (PathP (λ i → ℂ.Arrow (p i) 𝒜) xa ya) × (PathP (λ i → ℂ.Arrow (p i) ℬ) xb yb)) - ≅ Σ (X ℂ.≊ Y) (λ iso - → let p = ℂ.isoToId iso - in - ( PathP (λ i → ℂ.Arrow (p i) 𝒜) xa ya) - × PathP (λ i → ℂ.Arrow (p i) ℬ) xb yb - ) + step1 : T1 ≅ T2 step1 = symIso (isoSigFst @@ -100,14 +104,7 @@ module _ {ℓa ℓb : Level} (ℂ : Category ℓa ℓb) (symIso (_ , ℂ.asTypeIso {X} {Y}) .snd) ) - step2 - : Σ (X ℂ.≊ Y) (λ iso - → let p = ℂ.isoToId iso - in - ( PathP (λ i → ℂ.Arrow (p i) 𝒜) xa ya) - × PathP (λ i → ℂ.Arrow (p i) ℬ) xb yb - ) - ≅ ((X , xa , xb) ≊ (Y , ya , yb)) + step2 : T2 ≅ T3 step2 = ( λ{ (iso@(f , f~ , inv-f) , p , q) → ( f , sym (ℂ.domain-twist-sym iso p) , sym (ℂ.domain-twist-sym iso q)) From 49f1262b2c41cbb177df4e5a04de232a65a19cdf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Frederik=20Hangh=C3=B8j=20Iversen?= Date: Tue, 29 May 2018 15:24:18 +0200 Subject: [PATCH 33/33] Update change log --- CHANGELOG.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6bb631b..e5da62c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,13 @@ Change log ========= +Version 1.6.0 +------------- + +This version mainly contains changes to the report. + +This is the version I submit for my MSc.. + Version 1.5.0 ------------- Prove postulates in `Cat.Wishlist`: