Tealeaves.Classes.Kleisli.Theory.TraversableMonad

From Tealeaves Require Export
  Classes.Kleisli.ContainerMonad
  Classes.Kleisli.TraversableMonad
  Classes.Kleisli.Theory.TraversableFunctor
  Classes.Kleisli.Theory.ContainerMonad.

Import Monoid.Notations.
Import Applicative.Notations.
Import TraversableFunctor.Notations.
Import TraversableMonad.Notations.
Import ContainerFunctor.Notations.
Import Subset.Notations.

#[local] Generalizable Variables U T G A B C ϕ M.
#[local] Arguments ret T%function_scope {Return} {A}%type_scope _.

Import Kleisli.TraversableMonad.DerivedInstances.

Theory of Traversable Monads

Section traversable_monad_theory.

  Context
    `{ret_inst: Return T}
    `{Map_T_inst: Map T}
    `{Traverse_T_inst: Traverse T}
    `{Bind_T_inst: Bind T T}
    `{Bindt_T_inst: Bindt T T}
    `{ToSubset_T_inst: ToSubset T}
    `{! Compat_Map_Bindt T T}
    `{! Compat_Traverse_Bindt T T}
    `{! Compat_Bind_Bindt T T}
    `{! Compat_ToSubset_Traverse T}.

  Context
    `{Map_U_inst: Map U}
    `{Traverse_U_inst: Traverse U}
    `{Bind_U_inst: Bind T U}
    `{Bindt_U_inst: Bindt T U}
    `{ToSubset_U_inst: ToSubset U}
    `{! Compat_Map_Bindt T U}
    `{! Compat_Traverse_Bindt T U}
    `{! Compat_Bind_Bindt T U}
    `{! Compat_ToSubset_Traverse U}.

  Context
    `{Monad_inst: ! TraversableMonad T}
    `{Module_inst: ! TraversableRightPreModule T U}.

mapReduce on Traversble Monads

  Lemma mapReduce_bindt `{Applicative G} `{Monoid M}:
     `(g: B M) `(f: A G (T B)),
      map (mapReduce g) bindt (U := U) f =
        mapReduce (T := U) (map (mapReduce g) f).
  Proof.
    intros. unfold mapReduce.
    rewrite (traverse_bindt (G1 := G) (G2 := const M) A B False).
    rewrite 2(traverse_to_bindt).
    reassociate <- on right.
    unfold_ops @Map_const.
    change (fun (x: ?A) ⇒ x) with (@id A).
    do 2 change (id ?f) with f.
    fequal.
    - ext A' B' f'.
      unfold Map_compose, Map_const, const.
      unfold map at 2.
      now rewrite (fun_map_id (F := G)).
    - ext A' B' [a b].
      unfold Mult_compose, Mult_const.
      unfold compose in ×.
      unfold const in ×.
      cbn.
      reflexivity.
  Qed.

  Lemma mapReduce_bind `{Monoid M}:
     `(g: B M) `(f: A T B),
      mapReduce g bind (U := U) f = mapReduce (mapReduce g f).
  Proof.
    intros. unfold mapReduce.
    rewrite (traverse_bind (G2 := const M) A B False).
    rewrite traverse_to_bindt.
    rewrite traverse_to_bindt.
    reflexivity.
  Qed.

  Lemma mapReduce_ret `{Monoid M}: `(f: A M),
      mapReduce f ret T = f.
  Proof.
    intros. unfold mapReduce.
    rewrite traverse_to_bindt.
    rewrite (ktm_bindt0 (G := const M) A False).
    reflexivity.
  Qed.

tolist on Traversable Monads

  Lemma tolist_ret: (A: Type),
      tolist ret T = ret list (A := A).
  Proof.
    intros.
    unfold_ops @Tolist_Traverse.
    now rewrite mapReduce_ret.
  Qed.

  Lemma tolist_bind: (A B: Type) (f: A T B),
      tolist bind f = bind (tolist f) tolist.
  Proof.
    intros.
    unfold_ops @Tolist_Traverse.
    rewrite (mapReduce_bind (ret list) f).
    rewrite (mapReduce_morphism (list A) (list B)).
    rewrite (kmon_bind0 (T := list)).
    reflexivity.
  Qed.

tosubset on Traversable Monads

  Lemma tosubset_hom1: (A: Type),
      tosubset ret T = ret subset (A := A).
  Proof.
    intros.
    rewrite tosubset_to_mapReduce.
    rewrite mapReduce_ret.
    reflexivity.
  Qed.

  Lemma tosubset_hom2: (A B: Type) (f: A T B),
      tosubset bind (U := U) f = bind (tosubset f) tosubset.
  Proof.
    intros.
    rewrite tosubset_to_mapReduce.
    rewrite mapReduce_bind.
    rewrite (tosubset_to_mapReduce (T := U)).
    rewrite (mapReduce_morphism (subset A) (subset B)).
    rewrite (kmon_bind0 (T := subset)).
    rewrite tosubset_to_mapReduce.
    reflexivity.
  Qed.

element_of on Traversable Monads

  Lemma element_of_hom1: (A: Type) (a: A),
      element_of a ret T = {{a}}.
  Proof.
    intros.
    ext a'.
    unfold element_of, compose.
    compose near a' on left.
    rewrite tosubset_hom1.
    cbv.
    now propext.
  Qed.

  Lemma element_of_hom2: (A B: Type) (f: A T B) (b: B),
      element_of b bind (U := U) f =
        mapReduce (op := Monoid_op_or) (unit := Monoid_unit_false)
          (mapReduce (op := Monoid_op_or) (unit := Monoid_unit_false)
             {{b}} f).
  Proof.
    intros.
    rewrite element_of_to_mapReduce.
    rewrite mapReduce_bind.
    reflexivity.
  Qed.

End traversable_monad_theory.