{-# OPTIONS --without-K --safe #-}
-- verbatim dual of Categories.Category.Construction.Properties.Kleisli
module Categories.Category.Construction.Properties.CoKleisli where

open import Level
import Relation.Binary.PropositionalEquality as ≑

open import Categories.Adjoint
open import Categories.Adjoint.Properties
open import Categories.Category
open import Categories.Functor using (Functor; _∘F_)
open import Categories.Functor.Equivalence
open import Categories.Comonad
import Categories.Morphism.Reasoning as MR

open import Categories.Adjoint.Construction.CoKleisli
open import Categories.Category.Construction.CoKleisli

private
  variable
    o β„“ e : Level
    π’ž π’Ÿ : Category o β„“ e

module _ {F : Functor π’ž π’Ÿ} {G : Functor π’Ÿ π’ž} (F⊣G : Adjoint F G) where
  private
    T : Comonad π’Ÿ
    T = adjointβ‡’comonad F⊣G

    π’Ÿβ‚œ : Category _ _ _
    π’Ÿβ‚œ = CoKleisli T

    module π’ž = Category π’ž
    module π’Ÿ = Category π’Ÿ
    module π’Ÿβ‚œ = Category π’Ÿβ‚œ


    module T = Comonad T
    module F = Functor F
    module G = Functor G

    open Adjoint F⊣G

  -- Maclane's Comparison Functor
  ComparisonF : Functor π’Ÿβ‚œ π’ž
  ComparisonF = record
   { Fβ‚€ = Ξ» X β†’ G.Fβ‚€ X
   ; F₁ = Ξ» {A} {B} f β†’ π’ž [ (G.F₁ f) ∘ unit.Ξ· (G.Fβ‚€ A) ]
   ; identity = Ξ» {A} β†’ zag
   ; homomorphism = Ξ» {X} {Y} {Z} {f} {g} β†’ begin
      G.F₁ (g π’Ÿ.∘ F.F₁ (G.F₁ f) π’Ÿ.∘ F.F₁ (unit.Ξ· (G.Fβ‚€ X))) π’ž.∘ unit.Ξ· (G.Fβ‚€ X)             β‰ˆβŸ¨ pushΛ‘ G.homomorphism ⟩
      G.F₁ g π’ž.∘ G.F₁ ((F.F₁ (G.F₁ f)) π’Ÿ.∘ F.F₁ (unit.Ξ· (G.Fβ‚€ X))) π’ž.∘ unit.Ξ· (G.Fβ‚€ X)      β‰ˆβŸ¨ (refl⟩∘⟨ pushΛ‘ G.homomorphism) ⟩
      G.F₁ g π’ž.∘ G.F₁ (F.F₁ (G.F₁ f)) π’ž.∘ G.F₁ (F.F₁ (unit.Ξ· (G.Fβ‚€ X))) π’ž.∘ unit.Ξ· (G.Fβ‚€ X) β‰ˆβŸ¨ (refl⟩∘⟨ (refl⟩∘⟨ sym (unit.commute (unit.Ξ· (G.Fβ‚€ X))))) ⟩
      G.F₁ g π’ž.∘ G.F₁ (F.F₁ (G.F₁ f)) π’ž.∘ unit.Ξ· (G.Fβ‚€ (F.Fβ‚€ (G.Fβ‚€ X))) π’ž.∘ unit.Ξ· (G.Fβ‚€ X) β‰ˆβŸ¨ (refl⟩∘⟨ pullΛ‘ (sym (unit.commute (G.F₁ f)))) ⟩
      G.F₁ g π’ž.∘ (unit.Ξ· (G.Fβ‚€ Y) π’ž.∘ G.F₁ f) π’ž.∘ unit.Ξ· (G.Fβ‚€ X)                           β‰ˆβŸ¨ MR.assoc²δγ π’ž ⟩
      (G.F₁ g π’ž.∘ unit.Ξ· (G.Fβ‚€ Y)) π’ž.∘ G.F₁ f π’ž.∘ unit.Ξ· (G.Fβ‚€ X)                           ∎
   ; F-resp-β‰ˆ = Ξ» eq β†’ π’ž.∘-resp-β‰ˆ (G.F-resp-β‰ˆ eq) (Category.Equiv.refl π’ž)
   }
   where
    open π’ž.HomReasoning
    open π’ž.Equiv
    open MR π’ž

  private
    L = ComparisonF
    module L = Functor L
    module Gβ‚œ = Functor (Forgetful T)
    module Fβ‚œ = Functor (Cofree T)

  F∘L≑Forgetful : (F ∘F L) ≑F Forgetful T
  F∘L≑Forgetful = record
   { eqβ‚€ = Ξ» X β†’ ≑.refl
   ; eq₁ = eq-1
   }
   where
   open π’Ÿ.HomReasoning
   open MR π’Ÿ
   eq-1 : {X Y : π’Ÿ.Obj} (f : F.Fβ‚€ (G.Fβ‚€ X) π’Ÿ.β‡’ Y) β†’ π’Ÿ.id π’Ÿ.∘ F.F₁ (G.F₁ f π’ž.∘ unit.Ξ· (G.Fβ‚€ X)) π’Ÿ.β‰ˆ (F.F₁ (G.F₁ f) π’Ÿ.∘ F.F₁ (unit.Ξ· (G.Fβ‚€ X))) π’Ÿ.∘ π’Ÿ.id
   eq-1 {X} {Y} f = begin
    π’Ÿ.id π’Ÿ.∘ F.F₁ (G.F₁ f π’ž.∘ unit.Ξ· (G.Fβ‚€ X))          β‰ˆβŸ¨ id-comm-sym ⟩
    F.F₁ (G.F₁ f π’ž.∘ unit.Ξ· (G.Fβ‚€ X)) π’Ÿ.∘ π’Ÿ.id          β‰ˆβŸ¨ (F.homomorphism ⟩∘⟨refl) ⟩
    (F.F₁ (G.F₁ f) π’Ÿ.∘ F.F₁ (unit.Ξ· (G.Fβ‚€ X))) π’Ÿ.∘ π’Ÿ.id ∎

  L∘Cofree≑G : (L ∘F Cofree T) ≑F G
  L∘Cofree≑G = record
   { eqβ‚€ = Ξ» X β†’ ≑.refl
   ; eq₁ = eq-1
   }
   where
   open π’ž.HomReasoning
   open MR π’ž
   eq-1 : {X Y : π’Ÿ.Obj} (f : X π’Ÿ.β‡’ Y) β†’ π’ž.id π’ž.∘ G.F₁ (f π’Ÿ.∘ counit.Ξ· X) π’ž.∘ unit.Ξ· (G.Fβ‚€ X) π’ž.β‰ˆ G.F₁ f π’ž.∘ π’ž.id
   eq-1 {X} {Y} f = begin
    π’ž.id π’ž.∘ G.F₁ (f π’Ÿ.∘ counit.Ξ· X) π’ž.∘ unit.Ξ· (G.Fβ‚€ X)         β‰ˆβŸ¨ id-comm-sym ⟩
    (G.F₁ (f π’Ÿ.∘ counit.Ξ· X) π’ž.∘ unit.Ξ· (G.Fβ‚€ X)) π’ž.∘ π’ž.id       β‰ˆβŸ¨ (pushΛ‘ G.homomorphism ⟩∘⟨refl) ⟩
    (G.F₁ f π’ž.∘ G.F₁ (counit.Ξ· X) π’ž.∘ unit.Ξ· (G.Fβ‚€ X)) π’ž.∘ π’ž.id  β‰ˆβŸ¨ (elimΚ³ zag ⟩∘⟨refl) ⟩
    G.F₁ f π’ž.∘ π’ž.id                                              ∎