Definition Mbind2 {A B C:Type} (mab:monad (A*B)) (f:A→B→monad C) :=
  (λ st, let (st',ab):= Meval mab st in let m':=f (fst ab) (snd ab) in m' st'):monad C.Infix ">>==" := Mbind2 (at level 15, left associativity) : monad_scope.

(* Specifications: *)
Lemma le_lt_Mbind2_lt {A B C:Type} (mab:monad (A*B)) (f:A→B→monad C): Mle mab → (∀ a b, Mlt (f a b)) → Mlt (mab >>== f).
Lemma lt_le_Mbind2_lt {A B C:Type} (mab:monad (A*B)) (f:A→B→monad C): Mlt mab → (∀ a b, Mle (f a b)) → Mlt (mab >>== f).
Lemma eq_eq_Mbind2_eq {A B C:Type} (mab:monad (A*B)) (f:A→B→monad C): Meq mab → (∀ a b, Meq (f a b)) → Meq (mab >>== f).
Lemma lt_lt_Mbind2_lt {A B C:Type} (mab:monad (A*B)) (f:A→B→monad C): Mlt mab → (∀ a b, Mlt (f a b)) → Mlt (mab >>== f).
Lemma mono_mono_Mbind2_mono {A B C:Type} (mab:monad (A*B)) (f:A→B→monad C): Mmono mab → Mmono_two f → Mmono (mab >>== f).
Lemma Mbind2_triple {A B:Type} (ma1 ma2 ma3:monad A) (mb:monad B) (f:(A*A*A)→B→monad A) (P:A→Prop): (∀ st, P (snd (ma1 st))) → (∀ st, P (snd (ma2 st))) → (∀ st, P (snd (ma3 st))) → (∀ xyz, P (fst (fst xyz)) → P (snd (fst xyz)) → P (snd xyz) → (∀ b st, P (snd ((f xyz b) st)))) → ∀ st, P (snd ((ma1 >>+ ma2 >>++ ma3 >>+ mb >>== f) st)).
Lemma Mbind2_list {A B:Type} (ma1:monad A) (mal2 mal3:monad (list A)) (mb:monad B) (f:(A*(list A)*(list A))→B→monad A) (P:A→Prop): (∀ st, P (snd (ma1 st))) → (∀ st, Forall P (snd (mal2 st))) → (∀ st, Forall P (snd (mal3 st))) → (∀ xyz, P (fst (fst xyz)) → Forall P (snd (fst xyz)) → Forall P (snd xyz) → (∀ b st, P (snd ((f xyz b) st)))) → ∀ st, P (snd ((ma1 >>+ mal2 >>++ mal3 >>+ mb >>== f) st)).
Lemma all_le_lm_to_ml_le {A:Type} (lm:list (monad A)): Forall Mle lm → Mle (lm_to_ml lm).
Lemma all_lt_lm_to_ml_le {A:Type} (lm:list (monad A)): (Forall Mlt lm) → Mle (lm_to_ml lm).
Lemma lm_to_ml_length {A:Type} (lm: list (monad A)) st: length (snd (lm_to_ml lm st)) = length lm.
Lemma all_mono_lm_to_ml_mono {A:Type} (lm: list (monad A)): Forall Mmono lm → Mmono (lm_to_ml lm).