Theory Monad_Plus

section ‹Monad-Plus Class›

theory Monad_Plus
imports Monad
begin

hide_const (open) Fixrec.mplus

class plusU = tycon +
  fixes plusU :: "udom'a  udom'a  udom'a::tycon"

class functor_plus = plusU + "functor" +
  assumes fmapU_plusU [coerce_simp]:
    "fmapUf(plusUab) = plusU(fmapUfa)(fmapUfb)"
  assumes plusU_assoc:
    "plusU(plusUab)c = plusUa(plusUbc)"

class monad_plus = plusU + monad +
  assumes bindU_plusU:
    "bindU(plusUxsys)k = plusU(bindUxsk)(bindUysk)"
  assumes plusU_assoc':
    "plusU(plusUab)c = plusUa(plusUbc)"

instance monad_plus  functor_plus
by standard (simp_all only: fmapU_eq_bindU bindU_plusU plusU_assoc')

definition fplus :: "'a'f::functor_plus  'a'f  'a'f"
  where "fplus = coerce(plusU :: udom'f  _)"

lemma fmap_fplus:
  fixes f :: "'a  'b" and a b :: "'a'f::functor_plus"
  shows "fmapf(fplusab) = fplus(fmapfa)(fmapfb)"
unfolding fmap_def fplus_def
by (simp add: coerce_simp)

lemma fplus_assoc:
  fixes a b c :: "'a'f::functor_plus"
  shows "fplus(fplusab)c = fplusa(fplusbc)"
unfolding fplus_def
by (simp add: coerce_simp plusU_assoc)

abbreviation mplus :: "'a'm::monad_plus  'a'm  'a'm"
  where "mplus  fplus"

lemmas mplus_def = fplus_def [where 'f="'m::monad_plus" for f]
lemmas fmap_mplus = fmap_fplus [where 'f="'m::monad_plus" for f]
lemmas mplus_assoc = fplus_assoc [where 'f="'m::monad_plus" for f]

lemma bind_mplus:
  fixes a b :: "'a'm::monad_plus"
  shows "bind(mplusab)k = mplus(bindak)(bindbk)"
unfolding bind_def mplus_def
by (simp add: coerce_simp bindU_plusU)

lemma join_mplus:
  fixes xss yss :: "('a'm)'m::monad_plus"
  shows "join(mplusxssyss) = mplus(joinxss)(joinyss)"
by (simp add: join_def bind_mplus)

end