Tealeaves.Adapters.CategoricalToKleisli.DecoratedTraversableMonad

From Tealeaves Require Import
  Classes.Categorical.DecoratedTraversableMonad
  Classes.Kleisli.DecoratedTraversableMonad
  CategoricalToKleisli.DecoratedMonad
  CategoricalToKleisli.DecoratedFunctor (cobind_dec).

Import Product.Notations.
Import Kleisli.Monad.Notations.
Import Kleisli.DecoratedTraversableMonad.Notations.
Import Categorical.Monad.Notations.
Import Categorical.TraversableFunctor.Notations.
Import Strength.Notations.

#[local] Generalizable Variables W T G ϕ A B C.

#[local] Tactic Notation "bring" constr(x) "and" constr(y) "together" :=
  change (?f x y ?g) with (f (x y) g).

Kleisli DTMs from Categorical DTMs

Derived Operations

Module DerivedOperations.

  #[export] Instance Binddt_Categorical
    (W: Type)
    (T: Type Type)
    `{Map T}
    `{Decorate W T}
    `{ApplicativeDist T}
    `{Join T}: Binddt W T T :=
  fun (G: Type Type) `{Map G} `{Pure G} `{Mult G} (A B: Type)
    (f: W × A G (T B)) ⇒
    map (F := G) join dist T G map f dec T.

End DerivedOperations.

Derived Instances

Module DerivedInstances.

  Import DerivedOperations.

  Section adapter.

    Context
      `{Categorical.DecoratedTraversableMonad.DecoratedTraversableMonad W T}.

    Context
      (G1: Type Type)
      `{Map G1} `{Pure G1} `{Mult G1} `{! Applicative G1}
      (G2: Type Type)
      `{Map G2} `{Pure G2} `{Mult G2} `{! Applicative G2}.

    Definition kcompose_dtm_alt {A B C} :=
      fun `(g: W × B G2 (T C))
        `(f: W × A G1 (T B))
      ⇒ (map (F := G1) ((map (F := G2) (μ))
                           δ T G2
                           map (F := T) (g μ (T := (W ×)))
                           σ
                           map (F := (W ×)) (dec T)))
           σ
           cobind (W := (W ×)) f.

    Lemma equiv' {A B C}:
       `(g: W × B G2 (T C))
         `(f: W × A G1 (T B)),
        g ⋆7 f =
          kcompose_dtm_alt g f.
    Proof.
      intros. unfold kc7.
      unfold_ops @Binddt_Categorical.
      ext [w a].
      unfold kcompose_dtm_alt.
      unfold compose at 6. cbn.
      unfold compose at 6.
      cbn. compose near (f (w, a)) on right.
      rewrite (fun_map_map (F := G1) (Functor := app_functor)).
      repeat fequal.
      ext t.
      unfold compose. cbn.
      compose near (dec T t).
      unfold compose. cbn.
      compose near (dec T t) on right.
      rewrite (fun_map_map (F := T)).
      unfold compose.
      repeat fequal.
      now ext [w' b].
    Qed.

  End adapter.

  Section with_monad.

    Context
      `{Categorical.DecoratedTraversableMonad.DecoratedTraversableMonad W T}.

    Theorem kdtm_binddt1_T {A}:
      binddt (G := fun AA) (η (T := T) extract) = @id (T A).
    Proof.
      unfold_ops @Binddt_Categorical.
      change (map (F := fun AA) ?f) with f.
      rewrite (dist_unit (F := T)).
      change (?mu id) with mu.
      rewrite <- fun_map_map.
      do 2 reassociateon left.
      rewrite dfun_dec_extract.
      reassociate <- on left.
      rewrite (mon_join_map_ret (T := T)).
      reflexivity.
    Qed.

    Theorem kdtm_binddt0_T:
        (G: Type Type) `{Map G} `{Pure G} `{Mult G} `{! Applicative G}
        (A B: Type)
        (f: W × A G (T B)),
        binddt f η (T := T) = f η (T := (W ×)).
    Proof.
      intros.
      unfold_ops @Binddt_Categorical.
      reassociateon left.
      rewrite (dmon_ret (W := W) (T := T)).
      reassociate <- on left.
      reassociatenear (η (A := W × A)).
      rewrite (natural (ϕ := @ret T _)).
      unfold_ops @Map_I.
      reassociate <- on left.
      reassociatenear (η (A := G (T B))).
      rewrite (trvmon_ret (T := T)).
      rewrite (fun_map_map (F := G) (Functor := app_functor)).
      rewrite (mon_join_ret (T := T)).
      rewrite (fun_map_id (F := G) (Functor := app_functor)).
      reflexivity.
    Qed.

    Section binddt_binddt.

      Context
        (G1: Type Type)
        `{Map G1} `{Pure G1} `{Mult G1} `{! Applicative G1}
        (G2: Type Type)
        `{Map G2} `{Pure G2} `{Mult G2} `{! Applicative G2}
        `(g: W × B G2 (T C)) `(f: W × A G1 (T B)).

      #[local] Arguments map (F)%function_scope {Map}
        {A B}%type_scope f%function_scope _.
      #[local] Arguments dist F%function_scope {ApplicativeDist}
        G%function_scope {H H0 H1} (A)%type_scope _.
      #[local] Arguments dec {E}%type_scope F%function_scope
        {Decorate} (A)%type_scope _.
      #[local] Arguments join {T}%function_scope
        {Join} (A)%type_scope _.

      Theorem kdtm_binddt2_T:
        map G1 (binddt (G := G2) g) binddt (G := G1) f =
          binddt (G := G1 G2) (g ⋆7 f).
      Proof.
        rewrite (equiv' _ _ g f).
        unfold kcompose_dtm_alt.
        (* ********** *)
        unfold binddt at 1 2; unfold Binddt_Categorical.
        assert (Functor G1) by now inversion Applicative0.
        assert (Functor G2) by now inversion Applicative1.
        (* Normalize associativity *)
        do 3 reassociate <-.
        (* Bring together <<map G1 (dec T B)>> and <<map G1 (μ B)>> *)
        rewrite <- (fun_map_map (F := G1) (Functor := app_functor)).
        bring (map G1 (dec T B)) and (map G1 (μ B)) together.
        rewrite (fun_map_map (F := G1) (Functor := app_functor)).
        rewrite dmon_join.
        (* Move <<dec T (T (W * B))>> towards <<dec T A>> *)
        reassociatenear (map T (dec T B)).
        rewrite <- (natural (ϕ := @dec W T _)).
        reassociate <- on left.
        rewrite <- (fun_map_map
                      (F := G1)
                      _ _ _
                      (dec T (T B))).
        reassociate <- on left.
        bring (map G1 (dec T (T B))) and (δ T G1 (T B)) together.
        rewrite <- (dtfun_compat (F := T) (G := G1)).
        do 2 reassociate <- on left.
        bring (dec T (G1 (T B))) and (map T f) together.
        rewrite <- (natural (ϕ := @dec W T _)).
        change (map (T prod W) f) with (map (T prod W) f).
        reassociate <- on left.
        reassociatenear (dec T A).
        (* Change decorate-then-decorate into decorate-then-duplicate *)
        rewrite dfun_dec_dec.
        reassociate <- on left.
        (* Now move <<μ B>> towards <<μ C>> *)
        unfold shift.
        rewrite incr_spec.
        change (μ (W × B) map T (map T (μ B) σ) map (T prod W) (dec T B)) with
          (μ (W × B) (map T (map T (μ B) σ) map (T prod W) (dec T B))).
        rewrite <- (fun_map_map (F := G1) (Functor := app_functor) _ _ _ _ (μ (W × B))).
        reassociate <- on left.
        rewrite (fun_map_map (F := G1) _ _ _ (μ (W × B))).
        reassociatenear (μ (W × B)).
        rewrite (natural (ϕ := join)).
        reassociate <- on left.
        bring (δ T G2 (T C)) and (μ (G2 (T C))) together.
        rewrite trvmon_join.
        do 2 reassociate <- on left.
        rewrite (fun_map_map (F := G2)).
        (* Change map-join-then-join into join-then-join *)
        rewrite (mon_join_join (T := T)).
        (* Now rearrange to match RHS *)
        rewrite <- (fun_map_map (F := G2)).
        change (map G2 (μ C) map G2 (map T (μ C)) δ T G2 (T (T C)) map T (δ T G2 (T C)) map (T T) g)
          with (map G2 (μ C) (map G2 (map T (μ C)) δ T G2 (T (T C)) map T (δ T G2 (T C)) map (T T) g)).
        rewrite <- (fun_map_map (F := G1)).
        change (map G1 (map G2 ?f)) with (map (G1 G2) f).
        change (map G2 (map T ?mu)) with (map (G2 T) mu).
        rewrite (natural (ϕ := dist T G2)).
        change (map (T G2) ?f) with (map T (map G2 f)).
        reassociatenear (map T (δ T G2 (T C))).
        rewrite (fun_map_map (F := T)).
        change (map (T prod W) ?f) with (map T (map (W ×) f)).
        rewrite (fun_map_map (F := T)).
        reassociatenear (δ T G1 (W × T B)).
        change (map G1 (map T ?f)) with (map (G1 T) f).
        rewrite (natural (ϕ := dist T G1) (A := (W × T B)) (B := (T (W × B)))).
        reassociate <- on left.
        change (map (T T) ?g) with (map T (map T g)).
        reassociatenear (map T (map T g)).
        rewrite (fun_map_map (F := T)).
        rewrite <- (fun_map_map (F := G1)).
        reassociate <- on left.
        change (map G1 (map T ?f)) with (map (G1 T) f).
        reassociatenear (δ T G1 (T (W × B))).
        rewrite (natural (ϕ := δ T G1)).
        reassociate <- on left.
        reassociatenear (map (T G1) (map T (μ B) σ map (prod W) (dec T B))).
        rewrite (fun_map_map (F := T G1)).
        change (map (T prod W) f) with (map T (map (prod W) f)).
        change (map (T G1) ?f) with (map T (map G1 f)).
        reassociatenear (map T cojoin).
        rewrite (fun_map_map (F := T)).
        reassociatenear (map T (map (prod W) f cojoin)).
        rewrite (fun_map_map (F := T)).
        reassociatenear (map T (σ (map (prod W) f cojoin))).
        rewrite (fun_map_map (F := T)).
        (* ********** *)
        unfold binddt, kc7, binddt.
        rewrite dist_linear.
        do 4 reassociate <- on left.
        reassociatenear (map T (μ B)).
        rewrite (fun_map_map (F := T)).
        replace (cobind f) with (map (prod W) f cojoin).
        reflexivity.
        ext [w a].
        reflexivity.
      Qed.

    End binddt_binddt.

    Lemma kdtm_morph_T:
       `{ApplicativeMorphism G1 G2 ϕ},
       (A B: Type) (f: W × A G1 (T B)),
        ϕ (T B) binddt (G := G1) f = binddt (G := G2) (ϕ (T B) f).
    Proof.
      introv morph. intros.
      unfold_ops @Binddt_Categorical.
      do 3 reassociate <- on left.
      fequal.
      unfold compose. ext t.
      rewrite appmor_natural.
      fequal.
      compose near (map f t).
      rewrite <- (dist_morph (F := T)).
      unfold compose. compose near t on left.
      now rewrite (fun_map_map (F := T)).
    Qed.

Typeclass Instances

    #[export] Instance: Kleisli.DecoratedTraversableMonad.DecoratedTraversableRightPreModule W T T :=
      {|
        kdtm_binddt1 := @kdtm_binddt1_T;
        kdtm_binddt2 := @kdtm_binddt2_T;
        kdtm_morph := @kdtm_morph_T;
      |}.

    #[export] Instance: Kleisli.DecoratedTraversableMonad.DecoratedTraversableMonad W T :=
      {| kdtm_binddt0 := @kdtm_binddt0_T;
         kdtm_monoid := dmon_monoid;
      |}.

  End with_monad.

End DerivedInstances.