{-# OPTIONS --without-K --safe #-}
module Categories.Category.Construction.Properties.Kleisli 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.Monad
import Categories.Morphism.Reasoning as MR

open import Categories.Adjoint.Construction.Kleisli
open import Categories.Category.Construction.Kleisli

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

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

    π’žβ‚œ : Category _ _ _
    π’žβ‚œ = Kleisli T

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


    module T = Monad T
    module F = Functor F
    module G = Functor G

    open Adjoint F⊣G

  -- Maclane's Comparison Functor
  ComparisonF : Functor π’žβ‚œ π’Ÿ
  ComparisonF = record
    { Fβ‚€ = Ξ» X β†’ F.Fβ‚€ X
    ; F₁ = Ξ» {A} {B} f β†’ π’Ÿ [ counit.Ξ· (F.Fβ‚€ B) ∘ F.F₁ f ]
    ; identity = zig
    ; homomorphism = Ξ» {X} {Y} {Z} {f} {g} β†’ begin
      π’Ÿ [ counit.Ξ· (F.Fβ‚€ Z) ∘ F.F₁ (π’ž [ π’ž [ G.F₁ (counit.Ξ· (F.Fβ‚€ Z)) ∘ G.F₁ (F.F₁ g)] ∘ f ])]                 β‰ˆβŸ¨ refl⟩∘⟨ F.homomorphism ⟩
      π’Ÿ [ counit.Ξ· (F.Fβ‚€ Z) ∘ π’Ÿ [ F.F₁ (π’ž [ G.F₁ (counit.Ξ· (F.Fβ‚€ Z)) ∘ G.F₁ (F.F₁ g) ]) ∘ F.F₁ f ] ]          β‰ˆβŸ¨ refl⟩∘⟨ F.homomorphism  ⟩∘⟨refl ⟩
      π’Ÿ [ counit.Ξ· (F.Fβ‚€ Z) ∘ π’Ÿ [ π’Ÿ [ F.F₁ (G.F₁ (counit.Ξ· (F.Fβ‚€ Z))) ∘ F.F₁ (G.F₁ (F.F₁ g)) ] ∘ F.F₁ f ] ]   β‰ˆβŸ¨ center⁻¹ refl refl ⟩
      π’Ÿ [ π’Ÿ [ counit.Ξ· (F.Fβ‚€ Z) ∘ F.F₁ (G.F₁ (counit.Ξ· (F.Fβ‚€ Z))) ] ∘ π’Ÿ [ F.F₁ (G.F₁ (F.F₁ g)) ∘ F.F₁ f ] ]   β‰ˆβŸ¨ counit.commute (counit.Ξ· (F.Fβ‚€ Z)) ⟩∘⟨refl ⟩
      π’Ÿ [ π’Ÿ [ counit.Ξ· (F.Fβ‚€ Z) ∘ (counit.Ξ· (F.Fβ‚€ (G.Fβ‚€ (F.Fβ‚€ Z)))) ] ∘ π’Ÿ [ F.F₁ (G.F₁ (F.F₁ g)) ∘ F.F₁ f ] ] β‰ˆβŸ¨ extendΒ² (counit.commute (F.F₁ g))  ⟩
      π’Ÿ [ π’Ÿ [ counit.Ξ· (F.Fβ‚€ Z) ∘ F.F₁ g ] ∘ π’Ÿ [ counit.Ξ· (F.Fβ‚€ Y) ∘ F.F₁ f ] ]                               ∎
    ; F-resp-β‰ˆ = Ξ» eq β†’ π’Ÿ.∘-resp-β‰ˆΚ³ (F.F-resp-β‰ˆ eq)
    }
    where
      open π’Ÿ.HomReasoning
      open π’Ÿ.Equiv
      open MR π’Ÿ

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

  G∘L≑Forgetful : (G ∘F L) ≑F Forgetful T
  G∘L≑Forgetful = record
    { eqβ‚€ = Ξ» X β†’ ≑.refl
    ; eq₁ = Ξ» {A} {B} f β†’ begin
      π’ž [ π’ž.id ∘ G.F₁ (π’Ÿ [ counit.Ξ· (F.Fβ‚€ B) ∘ F.F₁ f ]) ]        β‰ˆβŸ¨ π’ž.identityΛ‘ ⟩
      G.F₁ (π’Ÿ [ counit.Ξ· (F.Fβ‚€ B) ∘ F.F₁ f ])                      β‰ˆβŸ¨ G.homomorphism ⟩
      π’ž [ G.F₁ (counit.Ξ· (F.Fβ‚€ B)) ∘ G.F₁ (F.F₁ f) ]               β‰ˆΛ˜βŸ¨ π’ž.identityΚ³ ⟩
      π’ž [ π’ž [ G.F₁ (counit.Ξ· (F.Fβ‚€ B)) ∘ G.F₁ (F.F₁ f) ] ∘ π’ž.id ] ∎

    }
    where
      open π’ž.HomReasoning

  L∘Free≑F : (L ∘F Free T) ≑F F
  L∘Free≑F = record
    { eqβ‚€ = Ξ» X β†’ ≑.refl
    ; eq₁ = Ξ» {A} {B} f β†’ begin
      π’Ÿ [ π’Ÿ.id ∘ π’Ÿ [ counit.Ξ· (F.Fβ‚€ B) ∘ F.F₁ (π’ž [ unit.Ξ· B ∘ f ]) ] ] β‰ˆβŸ¨ π’Ÿ.identityΛ‘ ⟩
      π’Ÿ [ counit.Ξ· (F.Fβ‚€ B) ∘ F.F₁ (π’ž [ unit.Ξ· B ∘ f ]) ]               β‰ˆβŸ¨ pushΚ³ F.homomorphism ⟩
      π’Ÿ [ π’Ÿ [ counit.Ξ· (F.Fβ‚€ B) ∘ F.F₁ (unit.Ξ· B) ] ∘ F.F₁ f ]          β‰ˆβŸ¨ elimΛ‘ zig ⟩
      F.F₁ f                                                              β‰ˆΛ˜βŸ¨ π’Ÿ.identityΚ³ ⟩
      π’Ÿ [ F.F₁ f ∘ π’Ÿ.id ]                                               ∎
    }
    where
      open π’Ÿ.HomReasoning
      open MR π’Ÿ