Theory Error_Monad

section ‹Error monad›

theory Error_Monad
imports Monad_Plus
begin

subsection ‹Type definition›

tycondef 'a'e error = Err (lazy "'e") | Ok (lazy "'a")

lemma coerce_error_abs [simp]: "coerce(error_absx) = error_abs(coercex)"
apply (simp add: error_abs_def coerce_def)
apply (simp add: emb_prj_emb prj_emb_prj DEFL_eq_error)
done

lemma coerce_Err [simp]: "coerce(Errx) = Err(coercex)"
unfolding Err_def by simp

lemma coerce_Ok [simp]: "coerce(Okm) = Ok(coercem)"
unfolding Ok_def by simp

lemma fmapU_error_simps [simp]:
  "fmapUf(::udom'a error) = "
  "fmapUf(Erre) = Erre"
  "fmapUf(Okx) = Ok(fx)"
unfolding fmapU_error_def error_map_def fix_const
apply simp
apply (simp add: Err_def)
apply (simp add: Ok_def)
done

subsection ‹Monad class instance›

instantiation error :: ("domain") "{monad, functor_plus}"
begin

definition
  "returnU = Ok"

fixrec bindU_error :: "udom'a error  (udom  udom'a error)  udom'a error"
  where "bindU_error(Erre)f = Erre"
  | "bindU_error(Okx)f = fx"

lemma bindU_error_strict [simp]: "bindUk = (::udom'a error)"
by fixrec_simp

fixrec plusU_error :: "udom'a error  udom'a error  udom'a error"
  where "plusU_error(Erre)f = f"
  | "plusU_error(Okx)f = Okx"

lemma plusU_error_strict [simp]: "plusU( :: udom'a error) = "
by fixrec_simp

instance proof
  fix f g :: "udom  udom" and r :: "udom'a error"
  show "fmapUf(fmapUgr) = fmapU(Λ x. f(gx))r"
    by (induct r rule: error.induct) simp_all
next
  fix f :: "udom  udom" and r :: "udom'a error"
  show "fmapUfr = bindUr(Λ x. returnU(fx))"
    by (induct r rule: error.induct)
       (simp_all add: returnU_error_def)
next
  fix f :: "udom  udom'a error" and x :: "udom"
  show "bindU(returnUx)f = fx"
    by (simp add: returnU_error_def)
next
  fix r :: "udom'a error" and f g :: "udom  udom'a error"
  show "bindU(bindUrf)g = bindUr(Λ x. bindU(fx)g)"
    by (induct r rule: error.induct)
       simp_all
next
  fix f :: "udom  udom" and a b :: "udom'a error"
  show "fmapUf(plusUab) = plusU(fmapUfa)(fmapUfb)"
    by (induct a rule: error.induct) simp_all
next
  fix a b c :: "udom'a error"
  show "plusU(plusUab)c = plusUa(plusUbc)"
    by (induct a rule: error.induct) simp_all
qed

end

subsection ‹Transfer properties to polymorphic versions›

lemma fmap_error_simps [simp]:
  "fmapf(::'a'e error) = "
  "fmapf(Erre :: 'a'e error) = Erre"
  "fmapf(Okx :: 'a'e error) = Ok(fx)"
unfolding fmap_def [where 'f="'e error"]
by (simp_all add: coerce_simp)

lemma return_error_def: "return = Ok"
unfolding return_def returnU_error_def
by (simp add: coerce_simp eta_cfun)

lemma bind_error_simps [simp]:
  "bind( :: 'a'e error)f = "
  "bind(Erre :: 'a'e error)f = Erre"
  "bind(Okx :: 'a'e error)f = fx"
unfolding bind_def
by (simp_all add: coerce_simp)

lemma join_error_simps [simp]:
  "join = ( :: 'a'e error)"
  "join(Erre) = Erre"
  "join(Okx) = x"
unfolding join_def by simp_all

lemma fplus_error_simps [simp]:
  "fplusr = ( :: 'a'e error)"
  "fplus(Erre)r = r"
  "fplus(Okx)r = Okx"
unfolding fplus_def
by (simp_all add: coerce_simp)

end