{-# OPTIONS --cubical #-}

open import Level renaming (suc to lsuc)
open import Function
open import Cubical.Foundations.Prelude
open import Cubical.HITs.PropositionalTruncation

record Functor ( ℓ' : Level) : Set (lsuc (  ℓ')) where
  field
    F-obj : Set   Set ℓ'
    F-mor : {X Y : Set }  (X  Y)  F-obj X  F-obj Y
    F-id : (X : Set )  F-mor (id {A = X})  id {A = F-obj X}
    F-comp : {X Y Z : Set } (g : Y  Z) (f : X  Y)  F-mor (g  f)  F-mor g  F-mor f
open Functor

Idᶠ : ( : Level)  Functor  
F-obj (Idᶠ ) X = X
F-mor (Idᶠ ) f = f
F-id (Idᶠ ) X = refl
F-comp (Idᶠ ) g f = refl

_∘ᶠ_ : { ℓ' ℓ'' : Level}  Functor ℓ' ℓ''  Functor  ℓ'  Functor  ℓ''
F-obj (G ∘ᶠ F) X = F-obj G (F-obj F X)
F-mor (G ∘ᶠ F) f = F-mor G (F-mor F f)
F-id (G ∘ᶠ F) X = cong (F-mor G) (F-id F X)  (F-id G (F-obj F X))
F-comp (G ∘ᶠ F) g f = cong (F-mor G) (F-comp F g f)  (F-comp G (F-mor F g) (F-mor F f))

record _⇒_ { ℓ' : Level} (F G : Functor  ℓ') : Set (lsuc (  ℓ')) where
  open Functor F renaming (F-obj to F₀ ; F-mor to F₁)
  open Functor G renaming (F-obj to G₀ ; F-mor to G₁)
  field
    α : (X : Set )  F₀ X  G₀ X
    nat : (X Y : Set ) (f : X  Y)   (α Y  F₁ f  G₁ f  α X) ∥₁
open _⇒_

Idⁿ : { ℓ' : Level} (F : Functor  ℓ')  F  F
α (Idⁿ F) X x = x
nat (Idⁿ F) X Y f =  refl ∣₁

_∘ⁿ_ : { ℓ' : Level} {H G F : Functor  ℓ'}
      G  H  F  G  F  H
α   (β ∘ⁿ γ) X = α β X  α γ X
nat (β ∘ⁿ γ) X Y f = rec2 isPropPropTrunc      cong (α β Y ∘_)   cong (_∘ α γ X)  ∣₁) (nat γ X Y f) (nat β X Y f)

_∙ⁿ_ : { ℓ' ℓ'' : Level} {G G' : Functor ℓ' ℓ''} {F F' : Functor  ℓ'}
      G  G'  F  F'  (G ∘ᶠ F)  (G' ∘ᶠ F')
α (_∙ⁿ_ {_} {_} {_} {G} {G'} {F} {F'} β γ) X = F-mor G' (α γ X)  α β (F-obj F X)
nat (_∙ⁿ_ {_} {_} {_} {G} {G'} {F} {F'} β γ) X Y f = rec2 isPropPropTrunc      cong (F-mor G' (α γ Y) ∘_)  
                                                                          cong (_∘ α β (F-obj F X)) (sym (F-comp G' (α γ Y) (F-mor F f)) 
                                                                                                       cong (F-mor G')   F-comp G' (F-mor F' f) (α γ X)
                                                                                 )
                                                                       ∣₁
                                                            ) (nat β (F-obj F X) (F-obj F Y) (F-mor F f)) (nat γ X Y f)

record Monad ( ℓ' : Level) (T : Functor  ) : Set (lsuc (  ℓ')) where
  open Functor T renaming (F-obj to T₀ ; F-mor to T₁)
  field  
    η : Idᶠ   T
    μ : (T ∘ᶠ T)  T 
    μ-unit-l : α (μ ∘ⁿ (η ∙ⁿ (Idⁿ T)))  α (Idⁿ T)
    μ-unit-r : α (μ ∘ⁿ ((Idⁿ T) ∙ⁿ η))  α (Idⁿ T)
    μ-assoc : α (μ ∘ⁿ ((Idⁿ T) ∙ⁿ μ))  α (μ ∘ⁿ (μ ∙ⁿ (Idⁿ T)))

record _≅ᶠ_ { ℓ' : Level} (F G : Functor  ℓ') : Set (lsuc (  ℓ')) where
  field
    to≅ : F  G
    from≅ : G  F
    inv≅-1 : α (from≅ ∘ⁿ to≅)  α (Idⁿ F)
    inv≅-2 : α (to≅ ∘ⁿ from≅)  α (Idⁿ G)