Section BasicFacts.
Context {m : Type -> Type}.
Context {EqM : EqM m}.
Context {Mm : Monad m}.
Context {EqMP : @EqMProps m _ EqM}.
Context {ML : @MonadLaws m EqM Mm}.
Instance Proper_Kleisli_apply {a b} :
Proper (eq2 ==> eq ==> eqm) (@Kleisli_apply m a b).
Global Instance Functor_pure
: Functor Fun (Kleisli m) (fun x => x) (@pure m _).
Global Instance Proper_cat_Kleisli {a b c}
: @Proper (Kleisli m a b -> Kleisli m b c -> _)
(eq2 ==> eq2 ==> eq2) cat.
Local Opaque bind ret eqm.
Global Instance CatAssoc_Kleisli : CatAssoc (Kleisli m).
(** *** [id_ktree] respect identity laws *)
Global Instance CatIdL_Kleisli : CatIdL (Kleisli m).
Global Instance CatIdR_Kleisli : CatIdR (Kleisli m).
Global Instance Category_Kleisli : Category (Kleisli m).
Global Instance InitialObject_Kleisli : InitialObject (Kleisli m) void.
(** *** [pure] is well-behaved *)
(* SAZ: not sure about the naming conventions here. *)
Global Instance Proper_pure {A B} :
Proper (eq2 ==> eq2) (@pure _ _ A B).
Fact compose_pure {A B C} (ab : A -> B) (bc : B -> C) :
(pure ab >>> pure bc ⩯ pure (ab >>> bc))%cat.
Fact compose_pure_l {A B C D} (f: A -> B) (g: B -> C) (k: Kleisli m C D) :
(pure f >>> (pure g >>> k) ⩯ pure (g ∘ f) >>> k)%cat.
Fact compose_pure_r {A B C D} (f: B -> C) (g: C -> D) (k: Kleisli m A B) :
((k >>> pure f) >>> pure g ⩯ k >>> pure (g ∘ f))%cat.
Fact pure_cat {A B C}: forall (f:A -> B) (bc: Kleisli m B C),
pure f >>> bc ⩯ fun a => bc (f a).
Fact cat_pure {A B C}: forall (ab: Kleisli m A B) (g:B -> C),
(ab >>> pure g)
⩯ (map g ab).
Fact case_pure {A B C} (ac : A -> C) (bc : B -> C) :
case_ (pure ac) (pure bc)
⩯ pure (@case_ _ Fun _ _ _ _ _ ac bc).
(** *** [Unitors] lemmas *)
(* This is probably generalizable into [Basics.Category]. *)
Fact bimap_id_pure {A B C} (f : B -> C) :
bimap (id_ A) (pure f) ⩯ pure (bimap (id_ A) f).
Fact bimap_pure_id {A B C} (f : A -> B) :
bimap (pure f) (id_ C) ⩯ pure (bimap f id).
Global Instance Coproduct_Kleisli : Coproduct (Kleisli m) sum.
Global Instance bimap_id_kleisli : BimapId (Kleisli m) sum.

Lemma map_inl_case_kleisli:
forall (a1 b1 b2 c1 c2 : Type) (f1 : Kleisli m a1 b1) (g1 : Kleisli m b1 c1) (g2 : Kleisli m b2 c2),
map inl f1 >>> case_ (map inl g1) (map inr g2) ⩯ map inl (f1 >>> g1).