Theory Resumption_Transformer

section ‹Resumption monad transformer›

theory Resumption_Transformer
imports Monad_Plus
begin

subsection ‹Type definition›

text ‹The standard Haskell libraries do not include a resumption
monad transformer type; below is the Haskell definition for the one we
will use here.›

text_raw ‹
\begin{verbatim}
data ResT m a = Done a | More (m (ResT m a))
\end{verbatim}
›

text ‹The above datatype definition can be translated directly into
HOLCF using tycondef›. \medskip›

tycondef 'a('f::"functor") resT =
  Done (lazy "'a") | More (lazy "('a'f resT)'f")

lemma coerce_resT_abs [simp]: "coerce(resT_absx) = resT_abs(coercex)"
apply (simp add: resT_abs_def coerce_def)
apply (simp add: emb_prj_emb prj_emb_prj DEFL_eq_resT)
done

lemma coerce_Done [simp]: "coerce(Donex) = Done(coercex)"
unfolding Done_def by simp

lemma coerce_More [simp]: "coerce(Morem) = More(coercem)"
unfolding More_def by simp

lemma resT_induct [case_names adm bottom Done More]:
  fixes P :: "'a'f::functor resT  bool"
  assumes adm: "adm P"
  assumes bottom: "P "
  assumes Done: "x. P (Donex)"
  assumes More: "m f. ((r::'a'f resT). P (fr))  P (More(fmapfm))"
  shows "P r"
proof (induct r rule: resT.take_induct [OF adm])
  fix n show "P (resT_take nr)"
    apply (induct n arbitrary: r)
    apply (simp add: bottom)
    apply (case_tac r rule: resT.exhaust)
    apply (simp add: bottom)
    apply (simp add: Done)
    apply (simp add: More)
    done
qed

subsection ‹Class instance proofs›

lemma fmapU_resT_simps [simp]:
  "fmapUf(::udom'f::functor resT) = "
  "fmapUf(Donex) = Done(fx)"
  "fmapUf(Morem) = More(fmap(fmapUf)m)"
unfolding fmapU_resT_def resT_map_def
apply (subst fix_eq, simp)
apply (subst fix_eq, simp add: Done_def)
apply (subst fix_eq, simp add: More_def)
done

instance resT :: ("functor") "functor"
proof
  fix f g :: "udom  udom" and xs :: "udom'a resT"
  show "fmapUf(fmapUgxs) = fmapU(Λ x. f(gx))xs"
    by (induct xs rule: resT_induct, simp_all add: fmap_fmap)
qed

instantiation resT :: ("functor") monad
begin

fixrec bindU_resT :: "udom'a resT  (udom  udom'a resT)  udom'a resT"
  where "bindU_resT(Donex)f = fx"
  | "bindU_resT(Morem)f = More(fmap(Λ r. bindU_resTrf)m)"

lemma bindU_resT_strict [simp]: "bindUk = (::udom'a resT)"
by fixrec_simp

definition
  "returnU = Done"

instance proof
  fix f :: "udom  udom" and xs :: "udom'a resT"
  show "fmapUfxs = bindUxs(Λ x. returnU(fx))"
    by (induct xs rule: resT_induct)
       (simp_all add: fmap_fmap returnU_resT_def)
next
  fix f :: "udom  udom'a resT" and x :: "udom"
  show "bindU(returnUx)f = fx"
    by (simp add: returnU_resT_def)
next
  fix xs :: "udom'a resT" and h k :: "udom  udom'a resT"
  show "bindU(bindUxsh)k = bindUxs(Λ x. bindU(hx)k)"
    by (induct xs rule: resT_induct)
       (simp_all add: fmap_fmap)
qed

end

subsection ‹Transfer properties to polymorphic versions›

lemma fmap_resT_simps [simp]:
  "fmapf(::'a'f::functor resT) = "
  "fmapf(Donex :: 'a'f::functor resT) = Done(fx)"
  "fmapf(Morem :: 'a'f::functor resT) = More(fmap(fmapf)m)"
unfolding fmap_def [where 'f="'f resT"]
by (simp_all add: coerce_simp)

lemma return_resT_def: "return = Done"
unfolding return_def returnU_resT_def
by (simp add: coerce_simp eta_cfun)

lemma bind_resT_simps [simp]:
  "bind( :: 'a'f::functor resT)f = "
  "bind(Donex :: 'a'f::functor resT)f = fx"
  "bind(Morem :: 'a'f::functor resT)f = More(fmap(Λ r. bindrf)m)"
unfolding bind_def
by (simp_all add: coerce_simp)

lemma join_resT_simps [simp]:
  "join = ( :: 'a'f::functor resT)"
  "join(Donex) = x"
  "join(Morem) = More(fmapjoinm)"
unfolding join_def by simp_all

subsection ‹Nondeterministic interleaving›

text ‹In this section we present a more general formalization of the
nondeterministic interleaving operation presented in Chapter 7 of the
author's PhD thesis cite"holcf11". If both arguments are Done›, then zipRT› combines the results with the function
f› and terminates. While either argument is More›,
zipRT› nondeterministically chooses one such argument, runs
it for one step, and then calls itself recursively.›

fixrec zipRT ::
  "('a  'b  'c)  'a('m::functor_plus) resT  'b'm resT  'c'm resT"
  where zipRT_Done_Done:
    "zipRTf(Donex)(Doney) = Done(fxy)"
  | zipRT_Done_More:
    "zipRTf(Donex)(Moreb) =
      More(fmap(Λ r. zipRTf(Donex)r)b)"
  | zipRT_More_Done:
    "zipRTf(Morea)(Doney) =
      More(fmap(Λ r. zipRTfr(Doney))a)"
  | zipRT_More_More:
    "zipRTf(Morea)(Moreb) =
      More(fplus(fmap(Λ r. zipRTf(Morea)r)b)
                 (fmap(Λ r. zipRTfr(Moreb))a))"

lemma zipRT_strict1 [simp]: "zipRTfr = "
by fixrec_simp

lemma zipRT_strict2 [simp]: "zipRTfr = "
by (fixrec_simp, cases r, simp_all)

abbreviation apR (infixl  70)
  where "a  b  zipRTIDab"

text ‹Proofs that zipRT› satisfies the applicative functor laws:›

lemma zipRT_homomorphism: "Donef  Donex = Done(fx)"
  by simp

lemma zipRT_identity: "DoneID  r = r"
  by (induct r rule: resT_induct, simp_all add: fmap_fmap eta_cfun)

lemma zipRT_interchange: "r  Donex = Done(Λ f. fx)  r"
  by (induct r rule: resT_induct, simp_all add: fmap_fmap)

text ‹The associativity rule is the hard one!›

lemma zipRT_associativity: "Donecfcomp  r1  r2  r3 = r1  (r2  r3)"
proof (induct r1 arbitrary: r2 r3 rule: resT_induct)
  case (Done x1) thus ?case
  proof (induct r2 arbitrary: r3 rule: resT_induct)
    case (Done x2) thus ?case
    proof (induct r3 rule: resT_induct)
      case (More p3 c3) thus ?case (* Done/Done/More *)
        by (simp add: fmap_fmap)
    qed simp_all
  next
    case (More p2 c2) thus ?case
    proof (induct r3 rule: resT_induct)
      case (Done x3) thus ?case (* Done/More/Done *)
        by (simp add: fmap_fmap)
    next
      case (More p3 c3) thus ?case (* Done/More/More *)
        by (simp add: fmap_fmap fmap_fplus)
    qed simp_all
  qed simp_all
next
  case (More p1 c1) thus ?case
  proof (induct r2 arbitrary: r3 rule: resT_induct)
    case (Done y) thus ?case
    proof (induct r3 rule: resT_induct)
      case (Done x3) thus ?case
        by (simp add: fmap_fmap)
    next
      case (More p3 c3) thus ?case
        by (simp add: fmap_fmap)
    qed simp_all
  next
    case (More p2 c2) thus ?case
    proof (induct r3 rule: resT_induct)
      case (Done x3) thus ?case
        by (simp add: fmap_fmap fmap_fplus)
    next
      case (More p3 c3) thus ?case
        by (simp add: fmap_fmap fmap_fplus fplus_assoc)
    qed simp_all
  qed simp_all
qed simp_all

end