Theory Maybe_Monad

section ‹Maybe monad›

theory Maybe_Monad
imports Monad_Zero_Plus
begin

subsection ‹Type definition›

tycondef 'amaybe = Nothing | Just (lazy "'a")

lemma coerce_maybe_abs [simp]: "coerce(maybe_absx) = maybe_abs(coercex)"
apply (simp add: maybe_abs_def coerce_def)
apply (simp add: emb_prj_emb prj_emb_prj DEFL_eq_maybe)
done

lemma coerce_Nothing [simp]: "coerceNothing = Nothing"
unfolding Nothing_def by simp

lemma coerce_Just [simp]: "coerce(Justx) = Just(coercex)"
unfolding Just_def by simp

lemma fmapU_maybe_simps [simp]:
  "fmapUf(::udommaybe) = "
  "fmapUfNothing = Nothing"
  "fmapUf(Justx) = Just(fx)"
unfolding fmapU_maybe_def maybe_map_def fix_const
apply simp
apply (simp add: Nothing_def)
apply (simp add: Just_def)
done

subsection ‹Class instance proofs›

instance maybe :: "functor"
apply standard
apply (induct_tac xs rule: maybe.induct, simp_all)
done

instantiation maybe :: "{functor_zero_plus, monad_zero}"
begin

fixrec plusU_maybe :: "udommaybe  udommaybe  udommaybe"
  where "plusU_maybeNothingys = ys"
  | "plusU_maybe(Justx)ys = Justx"

lemma plusU_maybe_strict [simp]: "plusUys = (::udommaybe)"
by fixrec_simp

fixrec bindU_maybe :: "udommaybe  (udom  udommaybe)  udommaybe"
  where "bindU_maybeNothingk = Nothing"
  | "bindU_maybe(Justx)k = kx"

lemma bindU_maybe_strict [simp]: "bindUk = (::udommaybe)"
by fixrec_simp

definition zeroU_maybe_def:
  "zeroU = Nothing"

definition returnU_maybe_def:
  "returnU = Just"

lemma plusU_Nothing_right: "plusUxsNothing = xs"
by (induct xs rule: maybe.induct) simp_all

lemma bindU_plusU_maybe:
  fixes xs ys :: "udommaybe" shows
  "bindU(plusUxsys)f = plusU(bindUxsf)(bindUysf)"
apply (induct xs rule: maybe.induct)
apply simp_all
oops

instance proof
  fix x :: "udom"
  fix f :: "udom  udom"
  fix h k :: "udom  udommaybe"
  fix xs ys zs :: "udommaybe"
  show "fmapUfxs = bindUxs(Λ x. returnU(fx))"
    by (induct xs rule: maybe.induct, simp_all add: returnU_maybe_def)
  show "bindU(returnUx)k = kx"
    by (simp add: returnU_maybe_def plusU_Nothing_right)
  show "bindU(bindUxsh)k = bindUxs(Λ x. bindU(hx)k)"
    by (induct xs rule: maybe.induct) simp_all
  show "plusU(plusUxsys)zs = plusUxs(plusUyszs)"
    by (induct xs rule: maybe.induct) simp_all
  show "bindUzeroUk = zeroU"
    by (simp add: zeroU_maybe_def)
  show "fmapUf(plusUxsys) = plusU(fmapUfxs)(fmapUfys)"
    by (induct xs rule: maybe.induct) simp_all
  show "fmapUfzeroU = (zeroU :: udommaybe)"
    by (simp add: zeroU_maybe_def)
  show "plusUzeroUxs = xs"
    by (simp add: zeroU_maybe_def)
  show "plusUxszeroU = xs"
    by (simp add: zeroU_maybe_def plusU_Nothing_right)
qed

end

subsection ‹Transfer properties to polymorphic versions›

lemma fmap_maybe_simps [simp]:
  "fmapf(::'amaybe) = "
  "fmapfNothing = Nothing"
  "fmapf(Justx) = Just(fx)"
unfolding fmap_def by simp_all

lemma fplus_maybe_simps [simp]:
  "fplus(::'amaybe)ys = "
  "fplusNothingys = ys"
  "fplus(Justx)ys = Justx"
unfolding fplus_def by simp_all

lemma fplus_Nothing_right [simp]:
  "fplusmNothing = m"
by (simp add: fplus_def plusU_Nothing_right)

lemma bind_maybe_simps [simp]:
  "bind(::'amaybe)f = "
  "bindNothingf = Nothing"
  "bind(Justx)f = fx"
unfolding bind_def fplus_def by simp_all

lemma return_maybe_def: "return = Just"
unfolding return_def returnU_maybe_def
by (simp add: coerce_cfun cfcomp1 eta_cfun)

lemma mzero_maybe_def: "mzero = Nothing"
unfolding mzero_def zeroU_maybe_def
by simp

lemma join_maybe_simps [simp]:
  "join(::'amaybemaybe) = "
  "joinNothing = Nothing"
  "join(Justxs) = xs"
unfolding join_def by simp_all

subsection ‹Maybe is not in monad_plus›

text ‹
  The maybe› type does not satisfy the law bind_mplus›.
›

lemma maybe_counterexample1:
  "a = Justx; b = ; kx = Nothing
     fplusab  k  fplus(a  k)(b  k)"
by simp

lemma maybe_counterexample2:
  "a = Justx; b = Justy; kx = Nothing; ky = Justz
     fplusab  k  fplus(a  k)(b  k)"
by simp

end