{-# OPTIONS --lossy-unification #-}
open import Cat.Functor.Adjoint
open import Cat.Prelude

import Cat.Functor.Reasoning
import Cat.Reasoning
module Cat.Functor.Adjoint.Compose where

Composition of adjunctions🔗

Suppose we have four functors and such that they “fit together”, i.e. the composites and both exist. What can we say about their composites? The hope is that they would again be adjoints, and this is indeed the case.

We prove this here by explicitly exhibiting the adjunction natural transformations and the triangle identities, which is definitely suboptimal for readability, but is the most efficient choice in terms of the resulting Agda program.

module _
    {o ℓ o₂ ℓ₂ o₃ ℓ₃}
    {A : Precategory o ℓ} {B : Precategory o₂ ℓ₂}
    {C : Precategory o₃ ℓ₃}
    {F : Functor A B} {G : Functor B A}
    {L : Functor B C} {R : Functor C B}
    (F⊣G : F ⊣ G)
    (L⊣R : L ⊣ R)
  where
  private
    module fg = __ F⊣G
    module lr = __ L⊣R
    module A = Cat.Reasoning A
    module B = Cat.Reasoning B
    module C = Cat.Reasoning C
    module F = Cat.Functor.Reasoning F
    module G = Cat.Functor.Reasoning G
    module L = Cat.Functor.Reasoning L
    module R = Cat.Functor.Reasoning R
    open __
    open _=>_
    module LF = Functor (L F∘ F)
    module GR = Functor (G F∘ R)
  LF⊣GR : (L F∘ F)(G F∘ R)
  LF⊣GR .unit .η x          = G.(lr.η _) A.∘ fg.η _
  LF⊣GR .counit .η x        = lr.ε _ C.∘ L.(fg.ε _)

  LF⊣GR .unit .is-natural x y f =
    (G.(lr.η _) A.∘ fg.η _) A.∘ f                ≡⟨ A.pullr (fg.unit.is-natural _ _ _)
    G.(lr.η _) A.∘ G.(F.₁ f) A.∘ fg.η _        ≡⟨ A.pulll (sym (G.F-∘ _ _))
    G.₁ ⌜ lr.η _ B.∘ F.₁ f ⌝ A.∘ fg.η _            ≡⟨ ap! (lr.unit.is-natural _ _ _)
    G.(R.(L.(F.₁ f)) B.∘ lr.η _) A.∘ fg.η _  ≡⟨ A.pushl (G.F-∘ _ _)
    GR.(LF.₁ f) A.∘ G.(lr.η _) A.(fg.η _)

  LF⊣GR .counit .is-natural x y f =
    (lr.ε _ C.∘ L.(fg.ε _)) C.∘ LF.(GR.₁ f) ≡⟨ C.pullr (sym (L.F-∘ _ _))
    lr.ε _ C.∘ L.₁ ⌜ fg.ε _ B.∘ F.(GR.₁ f) ⌝  ≡⟨ ap! (fg.counit.is-natural _ _ _)
    lr.ε _ C.∘ ⌜ L.(R.F₁ f B.∘ fg.ε _) ⌝      ≡⟨ ap! (L.F-∘ _ _)
    lr.ε _ C.∘ L.(R.F₁ f) C.∘ L.(fg.ε _)    ≡⟨ C.extendl (lr.counit.is-natural _ _ _)
    f C.∘ lr.ε _ C.∘ L.(fg.ε _)

  LF⊣GR .zig =
    (lr.ε _ C.∘ L.(fg.ε _)) C.∘ ⌜ LF.(G.(lr.η _) A.∘ fg.η _) ⌝ ≡⟨ C.extendr (ap! (LF.F-∘ _ _) ∙ L.extendl (fg.counit.is-natural _ _ _))
    (lr.ε _ C.∘ L.(lr.η _)) C.(L.(fg.ε _) C.∘ LF.(fg.η _))   ≡⟨ C.elimr (L.annihilate fg.zig)
    lr.ε _ C.∘ L.(lr.η _)                                          ≡⟨ lr.zig ⟩
    C.id                                                             ∎

  LF⊣GR .zag =
    GR.(lr.ε _ C.∘ L.(fg.ε _)) A.∘ G.(lr.η _) A.∘ fg.η _ ≡⟨ A.pulll (G.collapse (B.pushl (R.F-∘ _ _) ∙ ap₂ B.__ refl (sym (lr.unit.is-natural _ _ _))))
    G.₁ ⌜ R.(lr.ε _) B.∘ lr.η _ B.∘ fg.ε _ ⌝ A.∘ fg.η _      ≡⟨ ap! (B.cancell lr.zag)
    G.(fg.ε _) A.∘ fg.η _                                    ≡⟨ fg.zag ⟩
    A.id                                                       ∎
module _ {o ℓ} {C : Precategory o ℓ} where
  open Cat.Reasoning C
  open _=>_
  open __

  Id⊣Id : Id {C = C} ⊣ Id {C = C}
  Id⊣Id .unit .η x = id
  Id⊣Id .unit .is-natural x y f = id-comm-sym
  Id⊣Id .counit .η x = id
  Id⊣Id .counit .is-natural x y f = id-comm-sym
  Id⊣Id .zig = id2
  Id⊣Id .zag = id2