Jon Sterling, started 16th Dec 2022
\begin{code}
{-# OPTIONS --safe --without-K #-}
open import UF.FunExt
module Categories.NaturalTransformation (fe : Fun-Ext) where
open import Categories.Category fe
open import Categories.Functor fe
open import MLTT.Spartan
open import UF.Base
open import UF.Equiv
open import UF.Sets
open import UF.Sets-Properties
open import UF.Subsingletons
open import UF.Subsingletons-FunExt
open import UF.Subsingletons-Properties
module natural-transformation (๐ : precategory ๐ค ๐ฅ) (๐ : precategory ๐ค' ๐ฅ') where
 private
  module ๐ = precategory ๐
  module ๐ = precategory ๐
 open functor-of-precategories ๐ ๐
 module _ (F G : functor) where
  private
   module F = functor F
   module G = functor G
  transf : ๐ค โ ๐ฅ' ฬ
  transf = (A : ๐.ob) โ ๐.hom (F.ob A) (G.ob A)
  transf-is-set : is-set transf
  transf-is-set  =
   ฮ -is-set fe ฮป _ โ
   ๐.hom-is-set (F.ob _) (G.ob _)
  is-natural : transf โ ๐ค โ ๐ฅ โ ๐ฅ' ฬ
  is-natural ฮฑ =
   (A B : ๐.ob) (f : ๐.hom A B)
   โ ๐.seq (F.hom f) (ฮฑ B) ๏ผ ๐.seq (ฮฑ A) (G.hom f)
  record nat-transf : ๐ค โ ๐ฅ โ ๐ฅ' ฬ where
   constructor make
   field
    str : transf
    ax : is-natural str
  module nat-transf-as-sum where
   to-sum : nat-transf โ ฮฃ is-natural
   to-sum ฮฑ = let open nat-transf ฮฑ in str , ax
   from-sum : ฮฃ is-natural โ nat-transf
   from-sum ฮฑ = make (prโ ฮฑ) (prโ ฮฑ)
   to-sum-is-equiv : is-equiv to-sum
   prโ (prโ to-sum-is-equiv) = from-sum
   prโ (prโ to-sum-is-equiv) _ = refl
   prโ (prโ to-sum-is-equiv) = from-sum
   prโ (prโ to-sum-is-equiv) (make str ax) = refl
   equiv : nat-transf โ ฮฃ is-natural
   equiv = to-sum , to-sum-is-equiv
  being-natural-is-prop : {ฮฑ : transf} โ is-prop (is-natural ฮฑ)
  being-natural-is-prop =
   ฮ -is-prop fe ฮป _ โ
   ฮ -is-prop fe ฮป _ โ
   ฮ -is-prop fe ฮป _ โ
   ๐.hom-is-set _ _
  nat-transf-is-set : is-set nat-transf
  nat-transf-is-set =
   equiv-to-set
    nat-transf-as-sum.equiv
    (ฮฃ-is-set transf-is-set ฮป _ โ
     props-are-sets being-natural-is-prop)
  module _ {ฮฑ ฮฒ : nat-transf} where
   to-nat-transf-๏ผ : nat-transf.str ฮฑ ๏ผ nat-transf.str ฮฒ โ ฮฑ ๏ผ ฮฒ
   to-nat-transf-๏ผ h =
    equivs-are-lc
     nat-transf-as-sum.to-sum
     nat-transf-as-sum.to-sum-is-equiv
     (to-ฮฃ-๏ผ (h , being-natural-is-prop _ _))
  
 module _ (F : functor) where
  private module F = functor F
  transf-idn : transf F F
  transf-idn A = ๐.idn (F.ob A)
  abstract
   transf-idn-natural : is-natural F F transf-idn
   transf-idn-natural A B f =
    ๐.seq (F.hom f) (๐.idn _) ๏ผโจ ๐.idn-R _ _ _ โฉ
    F.hom f ๏ผโจ ๐.idn-L _ _ _ โปยน โฉ
    ๐.seq (๐.idn _) (F.hom f) โ
  nat-transf-idn : nat-transf F F
  nat-transf-idn = make transf-idn transf-idn-natural
 module _ (F G H : functor) where
  private
   module F = functor F
   module G = functor G
   module H = functor H
  module _ (ฮฑ : transf F G) (ฮฒ : transf G H) where
   transf-seq : transf F H
   transf-seq A = ๐.seq (ฮฑ A) (ฮฒ A)
   module _ (ฮฑ-nat : is-natural F G ฮฑ) (ฮฒ-nat : is-natural G H ฮฒ) where
    abstract
     transf-seq-natural : is-natural F H transf-seq
     transf-seq-natural A B f =
      ๐.seq (F.hom f) (๐.seq (ฮฑ B) (ฮฒ B))
       ๏ผโจ ๐.assoc _ _ _ _ _ _ _ โฉ
      ๐.seq (๐.seq (F.hom f) (ฮฑ B)) (ฮฒ B)
       ๏ผโจ ap (ฮป x โ ๐.seq x (ฮฒ B)) (ฮฑ-nat _ _ _) โฉ
      ๐.seq (๐.seq (ฮฑ A) (G.hom f)) (ฮฒ B)
       ๏ผโจ ๐.assoc _ _ _ _ _ _ _ โปยน โฉ
      ๐.seq (ฮฑ A) (๐.seq (G.hom f) (ฮฒ B))
       ๏ผโจ ap (๐.seq (ฮฑ A)) (ฮฒ-nat _ _ _) โฉ
      ๐.seq (ฮฑ A) (๐.seq (ฮฒ A) (H.hom f))
       ๏ผโจ ๐.assoc _ _ _ _ _ _ _ โฉ
      ๐.seq (๐.seq (ฮฑ A) (ฮฒ A)) (H.hom f) โ
  nat-transf-seq : nat-transf F G  โ nat-transf G H โ nat-transf F H
  nat-transf-seq ฮฑ ฮฒ =
   let module ฮฑ = nat-transf ฮฑ in
   let module ฮฒ = nat-transf ฮฒ in
   make
    (transf-seq ฮฑ.str ฮฒ.str)
    (transf-seq-natural ฮฑ.str ฮฒ.str ฮฑ.ax ฮฒ.ax)
 module _ (F G : functor) (ฮฑ : transf F G) where
  transf-idn-L : transf-seq F F G (transf-idn F) ฮฑ ๏ผ ฮฑ
  transf-idn-L =
   dfunext fe ฮป _ โ
   ๐.idn-L _ _ _
  transf-idn-R : transf-seq F G G ฮฑ (transf-idn G) ๏ผ ฮฑ
  transf-idn-R =
   dfunext fe ฮป _ โ
   ๐.idn-R _ _ _
 module _
  (F G H I : functor)
  (ฮฑ : transf F G)
  (ฮฒ : transf G H)
  (ฮณ : transf H I)
  where
  transf-assoc
   : transf-seq F G I ฮฑ (transf-seq G H I ฮฒ ฮณ)
   ๏ผ transf-seq F H I (transf-seq F G H ฮฑ ฮฒ) ฮณ
  transf-assoc =
   dfunext fe ฮป _ โ
   ๐.assoc _ _ _ _ _ _ _
 module nat-transf-laws (F G : functor) (ฮฑ : nat-transf F G) where
  module ฮฑ = nat-transf ฮฑ
  nat-transf-idn-L : nat-transf-seq _ _ _ (nat-transf-idn F) ฮฑ ๏ผ ฮฑ
  nat-transf-idn-L =
   to-nat-transf-๏ผ F G
    (transf-idn-L F G ฮฑ.str)
  nat-transf-idn-R : nat-transf-seq _ _ _ ฮฑ (nat-transf-idn G) ๏ผ ฮฑ
  nat-transf-idn-R =
   to-nat-transf-๏ผ F G
    (transf-idn-R F G ฮฑ.str)
 module _ (F G H I : functor) (ฮฑ : nat-transf F G) (ฮฒ : nat-transf G H) (ฮณ : nat-transf H I) where
  nat-transf-assoc
   : nat-transf-seq _ _ _ ฮฑ (nat-transf-seq _ _ _ ฮฒ ฮณ)
   ๏ผ nat-transf-seq _ _ _ (nat-transf-seq _ _ _ ฮฑ ฮฒ) ฮณ
  nat-transf-assoc =
   to-nat-transf-๏ผ F I
    (transf-assoc F G H I _ _ _)
 module functor-category where
  structure : category-structure (๐ค โ ๐ฅ โ ๐ค' โ ๐ฅ') (๐ค โ ๐ฅ โ ๐ฅ')
  structure = functor , nat-transf , nat-transf-idn , nat-transf-seq
  axioms : precategory-axioms structure
  axioms =
   let open nat-transf-laws in
   nat-transf-is-set ,
   nat-transf-idn-L ,
   nat-transf-idn-R ,
   nat-transf-assoc
  precat : precategory (๐ค โ ๐ฅ โ ๐ค' โ ๐ฅ') (๐ค โ ๐ฅ โ ๐ฅ')
  precat = make structure axioms
module _ {๐ : precategory ๐ฃ ๐ค} {๐ : precategory ๐ฃ' ๐ค'} {๐ : precategory ๐ฅ ๐ฆ} where
 private
  module ๐ = precategory ๐
  module ๐ = precategory ๐
  module ๐ = precategory ๐
 open functor-of-precategories
 open natural-transformation
 module horizontal-composition
  {F1 G1 : functor ๐ ๐}
  {F2 G2 : functor ๐ ๐}
  (ฮฑ : nat-transf ๐ ๐ F1 G1)
  (ฮฒ : nat-transf ๐ ๐ F2 G2)
  where
  private
   F3 = composite-functor.fun F1 F2
   G3 = composite-functor.fun G1 G2
   module F1 = functor F1
   module F2 = functor F2
   module G1 = functor G1
   module G2 = functor G2
   module F3 = functor F3
   module G3 = functor G3
   module ฮฑ = nat-transf ฮฑ
   module ฮฒ = nat-transf ฮฒ
  hcomp-str : transf ๐ ๐ F3 G3
  hcomp-str A = ๐.seq (ฮฒ.str (F1.ob A)) (G2.hom (ฮฑ.str A))
  abstract
   hcomp-ax : is-natural ๐ ๐ F3 G3 hcomp-str
   hcomp-ax A B f =
    ๐.seq (F2.hom (F1.hom f)) (๐.seq (ฮฒ.str (F1.ob B)) (G2.hom (ฮฑ.str B)))
     ๏ผโจ ๐.assoc _ _ _ _ _ _ _ โฉ
    ๐.seq (๐.seq (F3.hom f) (ฮฒ.str (F1.ob B))) (G2.hom (ฮฑ.str B))
     ๏ผโจ ap (ฮป x โ ๐.seq x _) h0 โฉ
    ๐.seq (๐.seq (ฮฒ.str (F1.ob A)) (G2.hom (F1.hom f))) (G2.hom (ฮฑ.str B))
     ๏ผโจ ๐.assoc _ _ _ _ _ _ _ โปยน โฉ
    ๐.seq (ฮฒ.str (F1.ob A)) (๐.seq (G2.hom (F1.hom f)) (G2.hom (ฮฑ.str B)))
     ๏ผโจ ap (๐.seq (ฮฒ.str (F1.ob A))) h1 โฉ
    ๐.seq (ฮฒ.str (F1.ob A)) (๐.seq (G2.hom (ฮฑ.str A)) (G3.hom f))
     ๏ผโจ ๐.assoc _ _ _ _ _ _ _ โฉ
    ๐.seq (๐.seq (ฮฒ.str (F1.ob A)) (G2.hom (ฮฑ.str A))) (G3.hom f) โ
    where
     h0
      : ๐.seq (F2.hom (F1.hom f)) (ฮฒ.str (F1.ob B))
      ๏ผ ๐.seq (ฮฒ.str (F1.ob A)) (G2.hom (F1.hom f))
     h0 = ฮฒ.ax (F1.ob A) (F1.ob B) (F1.hom f)
     h1
      : ๐.seq (G2.hom (F1.hom f)) (G2.hom (ฮฑ.str B))
      ๏ผ ๐.seq (G2.hom (ฮฑ.str A)) (G3.hom f)
     h1 =
      ๐.seq (G2.hom (F1.hom f)) (G2.hom (ฮฑ.str B))
       ๏ผโจ G2.preserves-seq _ _ _ _ _ โปยน โฉ
      G2.hom (๐.seq (F1.hom f) (ฮฑ.str B))
       ๏ผโจ ap G2.hom (ฮฑ.ax _ _ _) โฉ
      G2.hom (๐.seq (ฮฑ.str A) (G1.hom f))
       ๏ผโจ G2.preserves-seq _ _ _ _ _ โฉ
      ๐.seq (G2.hom (ฮฑ.str A)) (G3.hom f) โ
  hcomp : nat-transf ๐ ๐ F3 G3
  hcomp = make hcomp-str hcomp-ax
 module left-whiskering
  {G H : functor ๐ ๐}
  (W : functor ๐ ๐)
  (ฮฒ : nat-transf ๐ ๐ G H)
  where
  private
   W-G = composite-functor.fun W G
   W-H = composite-functor.fun W H
   module W = functor W
   module H = functor H
   module ฮฒ = nat-transf ฮฒ
  whisk-str : transf _ _ W-G W-H
  whisk-str A = ฮฒ.str (W.ob A)
  whisk-ax : is-natural _ _ W-G W-H whisk-str
  whisk-ax A B f = ฮฒ.ax (W.ob A) (W.ob B) (W.hom f)
  whisk : nat-transf _ _ W-G W-H
  whisk = make whisk-str whisk-ax
 module right-whiskering
  {G H : functor ๐ ๐}
  (ฮฒ : nat-transf _ _ G H)
  (W : functor ๐ ๐)
  where
  private
   G-W = composite-functor.fun G W
   H-W = composite-functor.fun H W
   module W = functor W
   module G = functor G
   module H = functor H
   module ฮฒ = nat-transf ฮฒ
  whisk-str : transf _ _ G-W H-W
  whisk-str A = W.hom (ฮฒ.str A)
  whisk-ax : is-natural _ _ G-W H-W whisk-str
  whisk-ax A B f =
   ๐.seq (W.hom (G.hom f)) (W.hom (ฮฒ.str B)) ๏ผโจ W.preserves-seq _ _ _ _ _ โปยน โฉ
   W.hom (๐.seq (G.hom f) (ฮฒ.str B)) ๏ผโจ ap W.hom (ฮฒ.ax _ _ _) โฉ
   W.hom (๐.seq (ฮฒ.str A) (H.hom f)) ๏ผโจ W.preserves-seq _ _ _ _ _ โฉ
   ๐.seq (W.hom (ฮฒ.str A)) (W.hom (H.hom f)) โ
  whisk : nat-transf ๐ ๐ G-W H-W
  whisk = make whisk-str whisk-ax
module
 _
  {๐ : precategory ๐ฃ ๐ค} {๐ : precategory ๐ฅ ๐ฆ}
  (open functor-of-precategories)
  (F : functor ๐ ๐)
 where
 open natural-transformation
 private
  module ๐ = precategory ๐
  module F = functor F
  1[๐] = identity-functor.fun ๐
  1[๐] = identity-functor.fun ๐
  1[๐]-F = composite-functor.fun 1[๐] F
  F-1[๐] = composite-functor.fun F 1[๐]
  [๐,๐] = functor-category.precat ๐ ๐
  module [๐,๐] = precategory [๐,๐]
 left-unitor : [๐,๐].hom 1[๐]-F F
 nat-transf.str left-unitor A = ๐.idn (F.ob A)
 nat-transf.ax left-unitor A B f =
  ๐.seq (F.hom f) (๐.idn (F.ob B)) ๏ผโจ ๐.idn-R _ _ _ โฉ
  F.hom f ๏ผโจ ๐.idn-L _ _ _ โปยน โฉ
  ๐.seq (๐.idn (F.ob A)) (F.hom f) โ
 left-unitor-inverse : [๐,๐].hom F 1[๐]-F
 nat-transf.str left-unitor-inverse A = ๐.idn (F.ob A)
 nat-transf.ax left-unitor-inverse A B f =
  ๐.seq (F.hom f) (๐.idn (F.ob B)) ๏ผโจ ๐.idn-R _ _ _ โฉ
  F.hom f ๏ผโจ ๐.idn-L _ _ _ โปยน โฉ
  ๐.seq (๐.idn (F.ob A)) (F.hom f) โ
 right-unitor : [๐,๐].hom F-1[๐] F
 nat-transf.str right-unitor A = ๐.idn (F.ob A)
 nat-transf.ax right-unitor A B f =
  ๐.seq (F.hom f) (๐.idn (F.ob B)) ๏ผโจ ๐.idn-R _ _ _ โฉ
  F.hom f ๏ผโจ ๐.idn-L _ _ _ โปยน โฉ
  ๐.seq (๐.idn (F.ob A)) (F.hom f) โ
 right-unitor-inverse : [๐,๐].hom F F-1[๐]
 nat-transf.str right-unitor-inverse A = ๐.idn (F.ob A)
 nat-transf.ax right-unitor-inverse A B f =
  ๐.seq (F.hom f) (๐.idn (F.ob B)) ๏ผโจ ๐.idn-R _ _ _ โฉ
  F.hom f ๏ผโจ ๐.idn-L _ _ _ โปยน โฉ
  ๐.seq (๐.idn (F.ob A)) (F.hom f) โ
 abstract
  left-unitor-is-section : [๐,๐].seq left-unitor left-unitor-inverse ๏ผ [๐,๐].idn 1[๐]-F
  left-unitor-is-section =
   to-nat-transf-๏ผ _ _ _ _
    (dfunext fe ฮป A โ
     ๐.seq (๐.idn (F.ob A)) (๐.idn (F.ob A)) ๏ผโจ ๐.idn-L _ _ _ โฉ
     ๐.idn (F.ob A) โ)
  left-unitor-is-retraction : [๐,๐].seq left-unitor-inverse left-unitor ๏ผ [๐,๐].idn F
  left-unitor-is-retraction =
   to-nat-transf-๏ผ _ _ _ _
    (dfunext fe ฮป A โ
     ๐.seq (๐.idn (F.ob A)) (๐.idn (F.ob A)) ๏ผโจ ๐.idn-L _ _ _ โฉ
     ๐.idn (F.ob A) โ)
  right-unitor-is-section : [๐,๐].seq right-unitor right-unitor-inverse ๏ผ [๐,๐].idn F-1[๐]
  right-unitor-is-section =
   to-nat-transf-๏ผ _ _ _ _
    (dfunext fe ฮป A โ
     ๐.seq (๐.idn (F.ob A)) (๐.idn (F.ob A)) ๏ผโจ ๐.idn-L _ _ _ โฉ
     ๐.idn (F.ob A) โ)
  right-unitor-is-retraction : [๐,๐].seq right-unitor-inverse right-unitor ๏ผ [๐,๐].idn F
  right-unitor-is-retraction =
   to-nat-transf-๏ผ _ _ _ _
    (dfunext fe ฮป A โ
     ๐.seq (๐.idn (F.ob A)) (๐.idn (F.ob A)) ๏ผโจ ๐.idn-L _ _ _ โฉ
     ๐.idn (F.ob A) โ)
module
 _
  {๐ : precategory ๐ฃ ๐ค} {๐ : precategory ๐ฅ ๐ฆ}
  {๐ : precategory ๐ฃ' ๐ค'} {๐ : precategory ๐ฅ' ๐ฆ'}
  (open functor-of-precategories)
  (F : functor ๐ ๐) (G : functor ๐ ๐) (H : functor ๐ ๐)
 where
 open natural-transformation
 private
  [๐,๐] = functor-category.precat ๐ ๐
  module [๐,๐] = precategory [๐,๐]
  module ๐ = precategory ๐
  module H = functor H
  module G = functor G
  module F = functor F
  F-G = composite-functor.fun F G
  G-H = composite-functor.fun G H
  F-[G-H] = composite-functor.fun F G-H
  [F-G]-H = composite-functor.fun F-G H
 associator : [๐,๐].hom F-[G-H] [F-G]-H
 nat-transf.str associator A = ๐.idn (H.ob (G.ob (F.ob A)))
 nat-transf.ax associator A B f =
  ๐.seq (H.hom (G.hom (F.hom f))) (๐.idn _) ๏ผโจ ๐.idn-R _ _ _ โฉ
  H.hom (G.hom (F.hom f)) ๏ผโจ ๐.idn-L _ _ _ โปยน โฉ
  ๐.seq (๐.idn _) (H.hom (G.hom (F.hom f))) โ
 associator-inverse : [๐,๐].hom [F-G]-H F-[G-H]
 nat-transf.str associator-inverse A = ๐.idn (H.ob (G.ob (F.ob A)))
 nat-transf.ax associator-inverse A B f =
  ๐.seq (H.hom (G.hom (F.hom f))) (๐.idn _) ๏ผโจ ๐.idn-R _ _ _ โฉ
  H.hom (G.hom (F.hom f)) ๏ผโจ ๐.idn-L _ _ _ โปยน โฉ
  ๐.seq (๐.idn _) (H.hom (G.hom (F.hom f))) โ
 abstract
  associator-is-section : [๐,๐].seq associator associator-inverse ๏ผ [๐,๐].idn F-[G-H]
  associator-is-section =
   to-nat-transf-๏ผ _ _ _ _
    (dfunext fe ฮป A โ
     ๐.seq (๐.idn _) (๐.idn _) ๏ผโจ ๐.idn-L _ _ _ โฉ
     ๐.idn _ โ)
  associator-is-retraction : [๐,๐].seq associator-inverse associator ๏ผ [๐,๐].idn [F-G]-H
  associator-is-retraction =
   to-nat-transf-๏ผ _ _ _ _
    (dfunext fe ฮป A โ
     ๐.seq (๐.idn _) (๐.idn _) ๏ผโจ ๐.idn-L _ _ _ โฉ
     ๐.idn _ โ)
\end{code}