module Monad where

open import Level

open import Category
import Functor
import Nat
import Adjoint

open Category.Category
open Functor.Functor
open Nat.Export
open Nat.Nat
open Adjoint.Export

record Monad {c₀ c₁ } (C : Category c₀ c₁ ) : Set (suc (c₀  c₁  )) where
  field
    MFunctor : Functor.Functor C C
    Mjoin : Nat.Nat (Functor.exp MFunctor 2) MFunctor
    Munit : Nat.Nat (Functor.identity C) MFunctor

  field
    join_join : {A : Obj C}  C [ C [ component Mjoin A  component Mjoin (fobj MFunctor A) ]  C [ component Mjoin A  fmap MFunctor (component Mjoin A) ] ]
    unit_MFunctor : {A : Obj C}  C [ C [ component Mjoin A  component Munit (fobj MFunctor A) ]  id C ]
    MFunctor_unit : {A : Obj C}  C [ C [ component Mjoin A  fmap MFunctor (component Munit A) ]  id C ]

Adjoint-Monad :  {C₀ C₁ } {C D : Category C₀ C₁ } {F : Functor.Functor C D} {G : Functor.Functor D C}  F  G  Monad C
Adjoint-Monad {C = C} {D} {F} {G} F⊣G = record {
  MFunctor = T;
  Mjoin = record {
    component = λ X  component (G F∘N ε N∘F F) X ;
    naturality = λ {a} {b} {f}  begin⟨ C 
      C [ component (G F∘N ε N∘F F) b  fmap G (fmap (Functor.compose F T) f) ] ≈⟨ sym-hom C (preserveComp G) 
      fmap G (D [ component ε (fobj F b)  fmap (Functor.compose F G) (fmap F f) ]) ≈⟨ Functor.preserveEq G (naturality ε) 
      fmap G (D [ fmap F f  component ε (fobj F a) ]) ≈⟨ preserveComp G 
      C [ fmap T f  component (G F∘N ε N∘F F) a ]
       };
  Munit = Adjoint.unit F⊣G;
  join_join = λ {A}  begin⟨ C 
    C [ component (G F∘N ε N∘F F) A  component (G F∘N ε N∘F F) (fobj T A) ] ≈⟨ sym-hom C (preserveComp G) 
    fmap G (D [ component ε (fobj F A)  component ε (fobj (Functor.compose F G) (fobj F A)) ]) ≈⟨ Functor.preserveEq G (sym-hom D (naturality ε)) 
    fmap G (D [ component ε (fobj F A)  fmap (Functor.compose F G) (component ε (fobj F A)) ]) ≈⟨ preserveComp G 
    C [ component (G F∘N ε N∘F F) A  fmap T (component (G F∘N ε N∘F F) A) ]
     ;
  unit_MFunctor = λ {A}  begin⟨ C 
    C [ component (G F∘N ε N∘F F) A  component η (fobj T A) ] ≈⟨ refl-hom C 
    C [ component (G F∘N ε) (fobj F A)  component (η N∘F G) (fobj F A) ] ≈⟨ sym-hom C (≈-composite C (leftId C) (trans-hom C (leftId C) (rightId C))) 
    C [ C [ id C  component (G F∘N ε) (fobj F A) ]  C [ id C  C [ component (η N∘F G) (fobj F A)  id C ] ] ] ≈⟨ refl-hom C 
    component (Nat.compose (Nat.compose {H = G} Nat.rightIdNat→ (G F∘N ε)) (Nat.compose (Nat.assocNat→ {F = G} {F} {G}) (Nat.compose (η N∘F G) Nat.leftIdNat←))) (fobj F A) ≈⟨ Adjoint.triangularR F⊣G {fobj F A} 
    component (id [ D , C ] {G}) (fobj F A) ≈⟨ refl-hom C 
    id C
     ;
  MFunctor_unit = λ {A}  begin⟨ C 
    C [ component (G F∘N ε N∘F F) A  fmap T (component η A) ] ≈⟨ refl-hom C 
    C [ fmap G (component ε (fobj F A))  fmap G (fmap F (component η A)) ] ≈⟨ sym-hom C (preserveComp G) 
    fmap G (D [ component ε (fobj F A)  fmap F (component η A) ]) ≈⟨ Functor.preserveEq G (≈-composite D (sym-hom D (leftId D)) (sym-hom D (trans-hom D (leftId D) (rightId D)))) 
    fmap G (D [ D [ id D  component ε (fobj F A) ]  D [ id D  D [ fmap F (component η A)  id D ] ] ]) ≈⟨ Functor.preserveEq G (refl-hom D) 
    fmap G (component (Nat.compose (Nat.compose Nat.leftIdNat→ (Adjoint.counit F⊣G N∘F F)) (Nat.compose {F = F} (Nat.assocNat← {F = F} {G} {F}) (Nat.compose {F = F} (F F∘N Adjoint.unit F⊣G) Nat.rightIdNat←))) A ) ≈⟨ Functor.preserveEq G (Adjoint.triangularL F⊣G {A}) 
    fmap G (component (id [ C , D ] {F}) A) ≈⟨ preserveId G 
    id C
     }
  where
    T = Functor.compose G F
    η = Adjoint.unit F⊣G
    ε = Adjoint.counit F⊣G