Tealeaves.Classes.Kleisli.Monad

From Tealeaves Require Export
  Tactics.Prelude
  Functors.Identity
  Classes.Categorical.Monad (Return, ret).

Import Functor.Notations.

#[local] Generalizable Variable T.

Monads

Operations

Class Bind (T U: Type Type) :=
  bind: (A B: Type), (A T B) U A U B.

#[global] Arguments bind {T} {U}%function_scope {Bind}
  {A B}%type_scope _%function_scope _.

Kleisli Composition

Definition kc {T: Type Type} `{Return T} `{Bind T T}
  {A B C: Type} (g: B T C) (f: A T B): (A T C) :=
  @bind T T _ B C g f.

#[local] Infix "⋆" := (kc) (at level 60): tealeaves_scope.

Typeclasses

Class RightPreModule
  (T U: Type Type)
  `{Return T} `{Bind T T} `{Bind T U} :=
  { kmod_bind1: (A: Type),
      bind (U := U) ret = @id (U A);
    kmod_bind2: (A B C: Type) (g: B T C) (f: A T B),
      bind (U := U) g bind f = bind (g f);
  }.

Class Monad (T: Type Type)
  `{Return_T: Return T}
  `{Bind_TT: Bind T T} :=
  { kmon_bind0: (A B: Type) (f: A T B),
      bind f ret = f;
    kmon_premod :> RightPreModule T T;
  }.

Class RightModule (T: Type Type) (U: Type Type)
  `{Return_T: Return T}
  `{Bind_TT: Bind T T}
  `{Bind_TU: Bind T U} :=
  { kmod_monad :> Monad T;
    kmod_premod :> RightPreModule T U;
  }.

#[local] Instance RightModule_Monad
  (T: Type Type)
  `{Monad_T: Monad T}: RightModule T T :=
  {| kmod_monad := Monad_T;
  |}.

(* right unit law of the monoid *)
Lemma kmon_bind1 `{Monad T}: (A: Type),
    @bind T T _ A A (@ret T _ A) = @id (T A).
Proof.
  apply kmod_bind1.
Qed.

(* associativity of the monoid *)
Lemma kmon_bind2 `{Monad T}:
   (A B C: Type) (g: B T C) (f: A T B),
    @bind T T _ B C g @bind T T _ A B f = @bind T T _ A C (g f).
Proof.
  apply kmod_bind2.
Qed.

Kleisli Category Laws

Section Monad_Kleisli_category.

  Context
    `{Monad T}.

  #[local] Generalizable Variables A B C D.

Left identity law

  Theorem kleisli_id_l: `(f: A T B),
      (@ret T _ B) f = f.
  Proof.
    intros. unfold kc.
    rewrite kmon_bind1.
    reflexivity.
  Qed.

Right identity law

  Theorem kleisli_id_r: `(g: B T C),
      g (@ret T _ B) = g.
  Proof.
    intros. unfold kc.
    rewrite kmon_bind0.
    reflexivity.
  Qed.

Associativity law

  Theorem kleisli_assoc:
     `(h: C T D) `(g: B T C) `(f: A T B),
      h (g f) = (h g) f.
  Proof.
    intros. unfold kc at 3.
    rewrite <- kmon_bind2.
    reflexivity.
  Qed.

End Monad_Kleisli_category.

Monad Homomorphisms

Class MonadHom (T U: Type Type)
  `{Return T} `{Bind T T}
  `{Return U} `{Bind U U}
  (ϕ: (A: Type), T A U A) :=
  { kmon_hom_bind: (A B: Type) (f: A T B),
      ϕ B bind f = bind (ϕ B f) ϕ A;
    kmon_hom_ret: (A: Type),
      ϕ A ret (T := T) = ret;
  }.

Class RightModuleHom (T U V: Type Type)
  `{Return T} `{Bind T U} `{Bind T V}
  (ϕ: (A: Type), U A V A) :=
  { kmod_hom_bind: (A B: Type) (f: A T B),
      ϕ B @bind T U _ A B f = @bind T V _ A B f ϕ A;
  }.

Class ParallelRightModuleHom (T T' U U': Type Type)
  `{Return T} `{Bind T U} `{Bind T' U'}
  (ψ: (A: Type), T A T' A)
  (ϕ: (A: Type), U A U' A) :=
  { kmodpar_hom_bind: (A B: Type) (f: A T B),
      ϕ B @bind T U _ A B f = @bind T' U' _ A B (ψ B f) ϕ A;
  }.

Derived Structures

Derived Operations

Module DerivedOperations.

  #[export] Instance Map_Bind (T U: Type Type)
    `{Return_T: Return T}
    `{Bind_TU: Bind T U}: Map U :=
  fun A B (f: A B) ⇒ @bind T U Bind_TU A B (@ret T Return_T B f).

End DerivedOperations.

Class Compat_Map_Bind
  (T: Type Type)
  (U: Type Type)
  `{Return_T: Return T}
  `{Map_U: Map U}
  `{Bind_TU: Bind T U}: Prop :=
  compat_map_bind:
    @Map_U = @DerivedOperations.Map_Bind T U Return_T Bind_TU.

#[export] Instance Compat_Map_Bind_Monad (T U: Type Type)
  `{Return_T: Return T} `{Bind_TU: Bind T U}:
  @Compat_Map_Bind T U Return_T
    (@DerivedOperations.Map_Bind T U Return_T Bind_TU) Bind_TU.
Proof.
  reflexivity.
Qed.

Lemma map_to_bind {T U: Type Type}
  `{Return_T: Return T}
  `{Map_U: Map U}
  `{Bind_TU: Bind T U}
  `{! Compat_Map_Bind T U}: {A B: Type} (f: A B),
    @map U Map_U A B f = @bind T U Bind_TU A B (@ret T Return_T B f).
Proof.
  rewrite compat_map_bind.
  reflexivity.
Qed.

Derived Kleisli Composition laws

Section derived_kleisli_composition_laws.

  Context
    `{Monad T} `{Map T} `{! Compat_Map_Bind T T}.

  #[local] Generalizable Variables A B C D.

Special cases for Kleisli composition

  Lemma kc_00: `(g: B C) `(f: A B),
      (ret g) (ret f) = ret (g f).
  Proof.
    intros. unfold kc.
    reassociate <-.
    rewrite kmon_bind0.
    reflexivity.
  Qed.

  Lemma kc_10: `(g: B T C) `(f: A B),
      g (ret f) = g f.
  Proof.
    intros. unfold kc.
    reassociate <-.
    rewrite kmon_bind0.
    reflexivity.
  Qed.

  Lemma kc_01: `(g: B C) `(f: A T B),
      (ret g) f = map g f.
  Proof.
    intros. unfold kc.
    rewrite map_to_bind.
    reflexivity.
  Qed.

Other rules for Kleisli composition

  Lemma kc_asc1: `(g: B C) `(h: C T D) `(f: A T B),
      (h g) f = h (map g f).
  Proof.
    intros. unfold kc.
    reassociate <-.
    rewrite map_to_bind.
    rewrite kmod_bind2.
    rewrite kc_10.
    reflexivity.
  Qed.

  Lemma kc_asc2: `(f: A B) `(g: B T C) `(h: C T D),
      h (g f) = (h g) f.
  Proof.
    intros. unfold kc.
    reflexivity.
  Qed.

End derived_kleisli_composition_laws.

Derived Composition Laws

Section derived_instances.

  #[local] Generalizable Variables U A B C.

  Context
    `{RightModule_TU: RightPreModule T U}
    `{Map_U: Map U}
    `{Map_T: Map T}
    `{! Compat_Map_Bind T U}
    `{! Compat_Map_Bind T T}
    `{Monad_T: ! Monad T}.

Composition between bind and map

  Lemma bind_map: `(g: B T C) `(f: A B),
      bind (U:= U) g map f = bind (g f).
  Proof.
    intros.
    rewrite map_to_bind.
    rewrite kmod_bind2.
    rewrite kc_10.
    reflexivity.
  Qed.

  Corollary map_bind: `(g: B C) `(f: A T B),
      map g bind (U := U) f = bind (map g f).
  Proof.
    intros.
    rewrite map_to_bind.
    rewrite kmod_bind2.
    rewrite map_to_bind.
    reflexivity.
  Qed.

Functor laws

  Lemma map_id: (A: Type),
      map (F := U) (@id A) = id.
  Proof.
    intros.
    rewrite map_to_bind.
    change (?f id) with f.
    rewrite kmod_bind1.
    reflexivity.
  Qed.

  Lemma map_map: (A B C: Type) (f: A B) (g: B C),
      map g map f = map (F := U) (g f).
  Proof.
    intros.
    rewrite map_to_bind.
    rewrite map_to_bind.
    rewrite kmod_bind2.
    rewrite kc_00.
    rewrite map_to_bind.
    reflexivity.
  Qed.

End derived_instances.

Derived Typeclass Instances

Module DerivedInstances.
  #[local] Generalizable Variables U.

  #[export] Instance Functor_RightModule
    `{RightModule_TU: RightModule T U}
    `{Map_U: Map U}
    `{! Compat_Map_Bind T U}:
    Functor U (Map_F := Map_U) :=
    {| fun_map_id := map_id;
       fun_map_map := map_map;
    |}.

  #[export] Instance Functor_Monad
    `{Monad_T: Monad T}
    `{Map_T: Map T}
    `{! Compat_Map_Bind T T}:
    Functor T := Functor_RightModule.

  Include DerivedOperations.

End DerivedInstances.

Naturality Properties

Return

#[export] Instance Natural_Return
  `{Monad_T: Monad T} `{Map_T: Map T}
  `{! Compat_Map_Bind T T}:
  Natural (@ret T Return_T).
Proof.
  constructor.
  - apply Functor_I.
  - apply DerivedInstances.Functor_Monad.
  - intros.
    rewrite map_to_bind.
    rewrite kmon_bind0.
    unfold_ops @Map_I.
    reflexivity.
Qed.

Monad Homomorphisms

#[export] Instance Natural_MonadHom
  `{Monad T1} `{Monad T2}
  `{Map T1} `{Map T2}
  `{! Compat_Map_Bind T1 T1}
  `{! Compat_Map_Bind T2 T2}
  (ϕ: (A: Type), T1 A T2 A)
  `{! MonadHom T1 T2 ϕ}: Natural ϕ.
Proof.
  constructor.
  - apply DerivedInstances.Functor_Monad.
  - apply DerivedInstances.Functor_Monad.
  - intros.
    rewrite map_to_bind.
    rewrite <- (kmon_hom_ret (T := T1) (U := T2)) at 1.
    rewrite map_to_bind.
    rewrite (kmon_hom_bind (T := T1) (U := T2)).
    reflexivity.
Qed.

Notations

Module Notations.
  Infix "⋆" := (kc) (at level 60): tealeaves_scope.
End Notations.