Theory CupCake_Semantics
section ‹CupCake semantics›
theory CupCake_Semantics
imports
CupCake_Env
CakeML.Matching
CakeML.Big_Step_Unclocked_Single
begin
fun cupcake_nsLookup :: "('m,'n,'v)namespace ⇒ 'n ⇒ 'v option " where
"cupcake_nsLookup (Bind v1 _) n = map_of v1 n"
lemma cupcake_nsLookup_eq[simp]: "nsLookup ns (Short n) = cupcake_nsLookup ns n"
by (cases ns) auto
fun cupcake_pmatch :: "((string),(string),(nat*tid_or_exn))namespace ⇒ pat ⇒ v ⇒(string*v)list ⇒((string*v)list)match_result " where
"cupcake_pmatch cenv (Pvar x) v0 env = Match ((x, v0)# env)" |
"cupcake_pmatch cenv (Pcon (Some (Short n)) ps) (Conv (Some (n', t')) vs) env =
(case cupcake_nsLookup cenv n of
Some (l, t)=>
if same_tid t t' ∧ (List.length ps = l) then
if same_ctor (n, t) (n',t') then
Matching.fold2 (λp v m. case m of
Match env ⇒ cupcake_pmatch cenv p v env
| m ⇒ m) Match_type_error ps vs (Match env)
else
No_match
else
Match_type_error
| _ => Match_type_error)" |
"cupcake_pmatch cenv _ _ _ = Match_type_error"
fun cupcake_match_result :: "_ ⇒ v ⇒(pat*exp)list ⇒ v ⇒ (exp × pat × (char list × v) list, v)result" where
"cupcake_match_result _ _ [] err_v = Rerr (Rraise err_v)" |
"cupcake_match_result cenv v0 ((p, e) # pes) err_v =
(if distinct (pat_bindings p []) then
(case cupcake_pmatch cenv p v0 [] of
Match env' ⇒ Rval (e, p, env') |
No_match ⇒ cupcake_match_result cenv v0 pes err_v |
Match_type_error ⇒ Rerr (Rabort Rtype_error))
else
Rerr (Rabort Rtype_error))"
lemma cupcake_match_resultE:
assumes "cupcake_match_result cenv v0 pes err_v = Rval (e, p, env')"
obtains init rest
where "pes = init @ (p, e) # rest"
and "distinct (pat_bindings p [])"
and "list_all (λ(p, e). cupcake_pmatch cenv p v0 [] = No_match ∧ distinct (pat_bindings p [])) init"
and "cupcake_pmatch cenv p v0 [] = Match env'"
using assms
proof (induction pes)
case (Cons pe pes)
obtain p0 e0 where "pe = (p0, e0)"
by fastforce
show thesis
proof (cases "distinct (pat_bindings p0 [])")
case True
thus ?thesis
proof (cases "cupcake_pmatch cenv p0 v0 []")
case No_match
show ?thesis
proof (rule Cons)
fix init rest
assume "pes = init @ (p, e) # rest"
assume "list_all (λ(p, e). cupcake_pmatch cenv p v0 [] = No_match ∧ distinct (pat_bindings p [])) init"
assume "distinct (pat_bindings p [])"
assume "cupcake_pmatch cenv p v0 [] = Match env'"
moreover have "pe # pes = ((p0, e0) # init) @ (p, e) # rest"
unfolding ‹pes = _› ‹pe = _› by simp
moreover have "list_all (λ(p, e). cupcake_pmatch cenv p v0 [] = No_match ∧ distinct (pat_bindings p [])) ((p0, e0) # init)"
apply auto
subgoal by fact
subgoal using True by simp
subgoal using ‹list_all _ _› by simp
done
moreover have "distinct (pat_bindings p [])"
by fact
ultimately show thesis
using Cons by blast
next
show "cupcake_match_result cenv v0 pes err_v = Rval (e, p, env')"
using Cons No_match True unfolding ‹pe = _› by auto
qed
next
case Match
with Cons show ?thesis
using True unfolding ‹pe = _› by force
next
case Match_type_error
with Cons show ?thesis
using True unfolding ‹pe = _› by force
qed
next
case False
hence False
using Cons unfolding ‹pe = _› by force
thus ?thesis ..
qed
qed simp
lemma cupcake_pmatch_eq:
"is_cupcake_pat pat ⟹ pmatch_single envC s pat v0 env = cupcake_pmatch envC pat v0 env"
proof (induct rule: pmatch_single.induct)
case 4
from is_cupcake_pat.elims(2)[OF 4(2)] show ?case
proof cases
case 2
then show ?thesis
using 4(1) apply -
apply simp
apply (auto split: option.splits match_result.splits)
apply (rule Matching.fold2_cong)
apply (auto simp: fun_eq_iff split: match_result.splits)
apply (metis in_set_conv_decomp_last list.pred_inject(2) list_all_append)
done
qed simp
qed auto
lemma cupcake_match_result_eq:
"cupcake_clauses pes ⟹
match_result env s v pes err_v =
map_result (λ(e, _, env'). (e, env')) id (cupcake_match_result (c env) v pes err_v)"
by (induction pes) (auto split: match_result.splits simp: cupcake_pmatch_eq pmatch_single_equiv)
context cakeml_static_env begin
lemma cupcake_nsBind_preserve:
"is_cupcake_ns ns ⟹ is_cupcake_value v0 ⟹ is_cupcake_ns (nsBind k v0 ns)"
by (cases ns) (auto elim: is_cupcake_ns.elims)
lemma cupcake_build_rec_preserve:
assumes "is_cupcake_all_env cl_env" "is_cupcake_ns env" "list_all (λ(_, _, e). is_cupcake_exp e) fs"
shows "is_cupcake_ns (build_rec_env fs cl_env env)"
proof -
have "is_cupcake_ns (foldr (λ(f, _) env'. nsBind f (Recclosure cl_env fs0 f) env') fs env)"
if "list_all (λ(_, _, e). is_cupcake_exp e) fs0"
for fs0
using ‹is_cupcake_ns env›
proof (induction fs arbitrary: env)
case (Cons f fs)
show ?case
apply (cases f, simp)
apply (rule cupcake_nsBind_preserve)
apply (rule Cons.IH)
apply (rule Cons)
using that assms by auto
qed auto
thus ?thesis
unfolding build_rec_env_def
using assms
by (simp add: cond_case_prod_eta)
qed
lemma cupcake_v_update_preserve:
assumes "is_cupcake_all_env env" "is_cupcake_ns (f (sem_env.v env))"
shows "is_cupcake_all_env (sem_env.update_v f env)"
using assms
by (metis is_cupcake_all_env.simps(1) is_cupcake_all_envE is_cupcake_nsE sem_env.collapse sem_env.record_simps(1) sem_env.record_simps(2) sem_env.sel(2))
lemma cupcake_nsAppend_preserve: "is_cupcake_ns ns1 ⟹ is_cupcake_ns ns2 ⟹ is_cupcake_ns (nsAppend ns1 ns2)"
by (auto elim!: is_cupcake_ns.elims)
lemma cupcake_alist_to_ns_preserve: "list_all (is_cupcake_value ∘ snd) env ⟹ is_cupcake_ns (alist_to_ns env)"
unfolding alist_to_ns_def
by simp
lemma cupcake_opapp_preserve:
assumes "do_opapp vs = Some (env, e)" "list_all is_cupcake_value vs"
shows "is_cupcake_all_env env" "is_cupcake_exp e"
proof -
obtain cl v0 where "vs = [cl, v0]"
using assms
by (cases vs rule: do_opapp.cases) auto
with assms have "is_cupcake_value cl" "is_cupcake_value v0"
by auto
have "is_cupcake_all_env env ∧ is_cupcake_exp e"
using ‹do_opapp vs = _› proof (cases rule: do_opapp_cases)
case (closure env' n arg)
then show ?thesis
using ‹is_cupcake_value cl› ‹is_cupcake_value v0› ‹vs = [cl, v0]›
by (auto intro: cupcake_v_update_preserve cupcake_nsBind_preserve dest:is_cupcake_all_envD(1))
next
case (recclosure env' funs name n)
hence "is_cupcake_all_env env'"
using ‹is_cupcake_value cl› ‹vs = [cl, v0]› by simp
have "(name, n, e) ∈ set funs"
using recclosure by (auto dest: map_of_SomeD)
hence "is_cupcake_exp e"
using ‹is_cupcake_value cl› ‹vs = [cl, v0]› recclosure
by (auto simp: list_all_iff)
thus ?thesis
using ‹is_cupcake_all_env env'› ‹is_cupcake_value cl› ‹is_cupcake_value v0› ‹vs = [cl, v0]› recclosure
unfolding ‹env = _›
using cupcake_build_rec_preserve cupcake_nsBind_preserve cupcake_v_update_preserve is_cupcake_all_envD(1)
by auto
qed
thus "is_cupcake_all_env env" "is_cupcake_exp e"
by simp+
qed
context begin
lemma cup_pmatch_list_length_neq:
"length vs ≠ length ps ⟹ Matching.fold2(λp v m. case m of
Match env ⇒ cupcake_pmatch cenv p v env
| m ⇒ m) Match_type_error ps vs m = Match_type_error"
by (induction ps vs arbitrary:m rule:List.list_induct2') auto
lemma cup_pmatch_list_nomatch:
"length vs = length ps ⟹ Matching.fold2(λp v m. case m of
Match env ⇒ cupcake_pmatch cenv p v env
| m ⇒ m) Match_type_error ps vs No_match = No_match"
by (induction ps vs rule:List.list_induct2') auto
lemma cup_pmatch_list_typerr:
"length vs = length ps ⟹ Matching.fold2(λp v m. case m of
Match env ⇒ cupcake_pmatch cenv p v env
| m ⇒ m) Match_type_error ps vs Match_type_error = Match_type_error"
by (induction ps vs rule:List.list_induct2') auto
private lemma cupcake_pmatch_list_preserve:
assumes " ⋀p v env. p ∈ set ps ∧ v ∈ set vs ⟶ list_all (is_cupcake_value ∘ snd) env ⟶ if_match (list_all (is_cupcake_value ∘ snd)) (cupcake_pmatch cenv p v env)" "list_all (is_cupcake_value ∘ snd) env"
shows "if_match (list_all (λa. is_cupcake_value (snd a))) (Matching.fold2
(λp v m. case m of
Match env ⇒ cupcake_pmatch cenv p v env
| m ⇒ m)
Match_type_error ps vs (Match env))"
using assms proof (induction ps vs arbitrary: env rule:list_induct2')
case (4 p ps v vs)
show ?case
proof (cases "cupcake_pmatch cenv p v env")
case No_match
then show ?thesis
by (cases "length ps = length vs") (auto simp:cup_pmatch_list_nomatch cup_pmatch_list_length_neq)
next
case Match_type_error
then show ?thesis
by (cases "length ps = length vs") (auto simp:cup_pmatch_list_typerr cup_pmatch_list_length_neq)
next
case (Match env')
then have env': "list_all (is_cupcake_value ∘ snd) env'"
using 4 by fastforce
then show ?thesis
apply (cases "length ps = length vs")
using 4 Match by fastforce+
qed
qed (auto simp: comp_def)
private lemma cupcake_pmatch_preserve0:
"is_cupcake_pat pat ⟹
is_cupcake_value v0 ⟹
list_all (is_cupcake_value ∘ snd) env ⟹
cupcake_c_ns envC ⟹
if_match (list_all (is_cupcake_value ∘ snd)) (cupcake_pmatch envC pat v0 env)"
proof (induction rule: cupcake_pmatch.induct)
case (2 cenv n ps n' t' vs env)
have p:"p ∈ set ps ⟹ is_cupcake_pat p" for p
using 2 by (metis Ball_set is_cupcake_pat.simps(2))
have v:"v ∈ set vs ⟹ is_cupcake_value v" for v
using 2 by (metis Ball_set is_cupcake_value.elims(2) v.distinct(11) v.distinct(13) v.inject(2))
show ?case
by (auto intro!: cupcake_pmatch_list_preserve split:if_splits option.splits) (metis 2 p v)+
qed (auto split: option.splits if_splits elim: is_cupcake_pat.elims is_cupcake_value.elims)
lemma cupcake_pmatch_preserve:
"is_cupcake_pat pat ⟹
is_cupcake_value v0 ⟹
list_all (is_cupcake_value ∘ snd) env ⟹
cupcake_c_ns envC ⟹
cupcake_pmatch envC pat v0 env = Match env' ⟹
list_all (is_cupcake_value ∘ snd) env'"
by (metis if_match.simps(1) cupcake_pmatch_preserve0)+
end
lemma cupcake_match_result_preserve:
"cupcake_c_ns envC ⟹
cupcake_clauses pes ⟹
is_cupcake_value v ⟹
if_rval (λ(e, p, env'). is_cupcake_pat p ∧ is_cupcake_exp e ∧ list_all (is_cupcake_value ∘ snd) env')
(cupcake_match_result envC v pes err_v)"
apply (induction pes)
apply (auto split: match_result.splits)
apply (rule cupcake_pmatch_preserve)
apply auto
done
lemma static_cenv_lookup:
assumes "cupcake_nsLookup static_cenv i = Some (len, b)"
obtains name where "b = TypeId (Short name)"
using assms static_cenv
apply (cases static_cenv; cases b)
apply (auto simp: list_all_iff split: prod.splits tid_or_exn.splits id0.splits dest!: map_of_SomeD elim!: ballE allE)
using static_cenv
apply (auto simp: list_all_iff split: prod.splits tid_or_exn.splits id0.splits dest!: map_of_SomeD elim!: ballE allE)
done
lemma cupcake_build_conv_preserve:
fixes v
assumes "list_all is_cupcake_value vs" "build_conv static_cenv (Some (Short i)) vs = Some v"
shows "is_cupcake_value v"
using assms
by (auto simp: build_conv.simps split: option.splits elim: static_cenv_lookup)
lemma cupcake_nsLookup_preserve:
assumes "is_cupcake_ns ns" "nsLookup ns n = Some v0"
shows "is_cupcake_value v0"
proof -
obtain vs where "list_all (is_cupcake_value ∘ snd) vs" "ns = Bind vs []"
using assms
by (auto elim: is_cupcake_ns.elims)
show ?thesis
proof (cases n)
case (Short id)
hence "(id, v0) ∈ set vs"
using assms unfolding ‹ns = _› by (auto dest: map_of_SomeD)
thus ?thesis
using ‹list_all (is_cupcake_value ∘ snd) vs›
by (auto simp: list_all_iff)
next
case Long
hence "nsLookup ns n = None"
unfolding ‹ns = _› by simp
thus ?thesis
using assms by auto
qed
qed
corollary match_all_preserve:
assumes "cupcake_match_result cenv v0 pes err_v = Rval (e, p, env')" "cupcake_c_ns cenv"
assumes "is_cupcake_value v0" "cupcake_clauses pes"
shows "list_all (is_cupcake_value ∘ snd) env'" "is_cupcake_exp e" "is_cupcake_pat p"
proof -
from assms obtain init rest
where "pes = init @ (p, e) # rest" and "cupcake_pmatch cenv p v0 [] = Match env'"
by (elim cupcake_match_resultE)
hence "(p, e) ∈ set pes"
by simp
thus "is_cupcake_exp e" "is_cupcake_pat p"
using assms by (auto simp: list_all_iff)
show "list_all (is_cupcake_value ∘ snd) env'"
by (rule cupcake_pmatch_preserve[where env = "[]"]) (fact | simp)+
qed
end
fun list_all2_shortcircuit where
"list_all2_shortcircuit P (x # xs) (y # ys) ⟷ (case y of Rval _ ⇒ P x y ∧ list_all2_shortcircuit P xs ys | Rerr _ ⇒ P x y)" |
"list_all2_shortcircuit P [] [] ⟷ True" |
"list_all2_shortcircuit P _ _ ⟷ False"
lemma list_all2_shortcircuit_induct[consumes 1, case_names nil cons_val cons_err]:
assumes "list_all2_shortcircuit P xs ys"
assumes "R [] []"
assumes "⋀x xs y ys. P x (Rval y) ⟹ list_all2_shortcircuit P xs ys ⟹ R xs ys ⟹ R (x # xs) (Rval y # ys)"
assumes "⋀x xs y ys. P x (Rerr y) ⟹ R (x # xs) (Rerr y # ys)"
shows "R xs ys"
using assms
proof (induction P xs ys rule: list_all2_shortcircuit.induct)
case (1 P x xs y ys)
thus ?case
by (cases y) auto
qed auto
lemma list_all2_shortcircuit_mono[mono]:
assumes "R ≤ Q"
shows "list_all2_shortcircuit R ≤ list_all2_shortcircuit Q"
proof
fix xs ys
assume "list_all2_shortcircuit R xs ys"
thus "list_all2_shortcircuit Q xs ys"
using assms by (induction xs ys rule: list_all2_shortcircuit_induct) auto
qed
lemma list_all2_shortcircuit_weaken: "list_all2_shortcircuit P xs ys ⟹ (⋀xs ys. P xs ys ⟹ Q xs ys) ⟹ list_all2_shortcircuit Q xs ys"
by (metis list_all2_shortcircuit_mono predicate2I rev_predicate2D)
lemma list_all2_shortcircuit_rval[simp]:
"list_all2_shortcircuit P xs (map Rval ys) ⟷ list_all2 (λx y. P x (Rval y)) xs ys" (is "?lhs ⟷ ?rhs")
proof
assume ?lhs thus ?rhs
by (induction "map Rval ys::('b, 'c) result list" arbitrary: ys rule: list_all2_shortcircuit_induct) auto
next
assume ?rhs thus ?lhs
by (induction rule: list_all2_induct) auto
qed
inductive cupcake_evaluate_single :: "all_env ⇒ exp ⇒ (v, v) result ⇒ bool" where
con1:
"do_con_check (c env) cn (length es) ⟹
list_all2_shortcircuit (cupcake_evaluate_single env) (rev es) rs ⟹
sequence_result rs = Rval vs ⟹
build_conv (c env) cn (rev vs) = Some v0 ⟹
cupcake_evaluate_single env (Con cn es) (Rval v0)" |
con2:
"¬ do_con_check (c env) cn (List.length es) ⟹
cupcake_evaluate_single env (Con cn es) (Rerr (Rabort Rtype_error))" |
con3:
"do_con_check (c env) cn (List.length es) ⟹
list_all2_shortcircuit (cupcake_evaluate_single env) (rev es) rs ⟹
sequence_result rs = Rerr err ⟹
cupcake_evaluate_single env (Con cn es) (Rerr err)" |
var1:
"nsLookup (sem_env.v env) n = Some v0 ⟹ cupcake_evaluate_single env (Var n) (Rval v0)" |
var2:
"nsLookup (sem_env.v env) n = None ⟹ cupcake_evaluate_single env (Var n) (Rerr (Rabort Rtype_error))" |
fn:
"cupcake_evaluate_single env (Fun n e) (Rval (Closure env n e))" |
app1:
"list_all2_shortcircuit (cupcake_evaluate_single env) (rev es) rs ⟹
sequence_result rs = Rval vs ⟹
do_opapp (rev vs) = Some (env', e) ⟹
cupcake_evaluate_single env' e bv ⟹
cupcake_evaluate_single env (App Opapp es) bv" |
app3:
"list_all2_shortcircuit (cupcake_evaluate_single env) (rev es) rs ⟹
sequence_result rs = Rval vs ⟹
do_opapp (rev vs) = None ⟹
cupcake_evaluate_single env (App Opapp es) (Rerr (Rabort Rtype_error))" |
app6:
"list_all2_shortcircuit (cupcake_evaluate_single env) (rev es) rs ⟹
sequence_result rs = Rerr err ⟹
cupcake_evaluate_single env (App op0 es) (Rerr err)" |
mat1:
"cupcake_evaluate_single env e (Rval v0) ⟹
cupcake_match_result (c env) v0 pes Bindv = Rval (e', _, env') ⟹
cupcake_evaluate_single (env (| sem_env.v := nsAppend (alist_to_ns env') (sem_env.v env) |)) e' bv ⟹
cupcake_evaluate_single env (Mat e pes) bv" |
mat1error:
"cupcake_evaluate_single env e (Rval v0) ⟹
cupcake_match_result (c env) v0 pes Bindv = Rerr err ⟹
cupcake_evaluate_single env (Mat e pes) (Rerr err)" |
mat2:
"cupcake_evaluate_single env e (Rerr err) ⟹
cupcake_evaluate_single env (Mat e pes) (Rerr err)"
context cakeml_static_env begin
context begin
private lemma cupcake_list_preserve0:
"list_all2_shortcircuit
(λe r. cupcake_evaluate_single env e r ∧ (is_cupcake_all_env env ⟶ is_cupcake_exp e ⟶ if_rval is_cupcake_value r)) es rs ⟹
is_cupcake_all_env env ⟹ list_all is_cupcake_exp es ⟹ sequence_result rs = Rval vs ⟹ list_all is_cupcake_value vs"
proof (induction es rs arbitrary: vs rule:list_all2_shortcircuit_induct)
case (cons_val _ _ _ rs)
thus ?case
by (cases "sequence_result rs") auto
qed auto
private lemma cupcake_single_preserve0:
"cupcake_evaluate_single env e res ⟹ is_cupcake_all_env env ⟹ is_cupcake_exp e ⟹ if_rval is_cupcake_value res"
proof (induction rule:cupcake_evaluate_single.induct)
case (con1 env cn es rs vs v0)
then obtain tid where cn: "cn = Some (Short tid)" and "list_all is_cupcake_exp (rev es)"
by (cases rule: is_cupcake_exp.cases[where x = "Con cn es"]) auto
hence "list_all is_cupcake_value (rev vs)" and "c env = static_cenv"
using cupcake_list_preserve0 con1
by (fastforce elim:is_cupcake_all_envE)+
then show ?case
using cupcake_build_conv_preserve con1 cn
by fastforce
next
case (app1 env es rs vs env' e bv)
hence "list_all is_cupcake_exp (rev es)"
by fastforce
hence "list_all is_cupcake_value (rev vs)"
using app1 cupcake_list_preserve0 by force
hence "is_cupcake_exp e" and "is_cupcake_all_env env'"
using app1 cupcake_opapp_preserve by blast+
then show ?case
using app1 by blast
next
case (mat1 env e v0 pes e' uu env' bv)
hence "cupcake_c_ns (c env)" "cupcake_clauses pes" "is_cupcake_value v0"
by (auto dest: is_cupcake_all_envD)
hence "list_all (is_cupcake_value ∘ snd) env'" and e': "is_cupcake_exp e'"
using cupcake_match_result_preserve[where envC = "c env" and v = v0 and pes = pes and err_v = Bindv, unfolded mat1, simplified]
by auto
have "is_cupcake_all_env (update_v (λ_. nsAppend (alist_to_ns env') (sem_env.v env)) env)"
apply (rule cupcake_v_update_preserve)
apply fact
apply (rule cupcake_nsAppend_preserve)
apply (rule cupcake_alist_to_ns_preserve)
apply fact
apply (rule is_cupcake_all_envD)
apply fact
done
then show ?case
using mat1 e' by blast
qed (auto intro: cupcake_nsLookup_preserve dest: is_cupcake_all_envD)
lemma cupcake_single_preserve:
"cupcake_evaluate_single env e (Rval res) ⟹ is_cupcake_all_env env ⟹ is_cupcake_exp e ⟹ is_cupcake_value res"
by (fastforce dest:cupcake_single_preserve0)
lemma cupcake_list_preserve:
"list_all2_shortcircuit (cupcake_evaluate_single env) es rs ⟹
is_cupcake_all_env env ⟹ list_all is_cupcake_exp es ⟹ sequence_result rs = Rval vs ⟹ list_all is_cupcake_value vs"
by (induction es rs arbitrary:vs rule:list_all2_shortcircuit_induct) (fastforce dest:cupcake_single_preserve)+
private lemma cupcake_list_correct_rval:
assumes "list_all2_shortcircuit
(λe r.
cupcake_evaluate_single env e r ∧
(is_cupcake_all_env env ⟶ is_cupcake_exp e ⟶ (∀(s::'a state). ∃s'. evaluate env s e (s', r))))
es rs" "is_cupcake_all_env env" "list_all is_cupcake_exp es" "sequence_result rs = Rval vs"
shows " ∃s'. evaluate_list (evaluate env) (s::'a state) es (s',Rval vs)"
using assms proof (induction es rs arbitrary: s vs rule:list_all2_shortcircuit_induct)
case (cons_val e es y ys)
have e: "is_cupcake_exp e" "list_all is_cupcake_exp es"
using cons_val by fastforce+
then obtain vs' where ys: "sequence_result ys = Rval vs'"
using cons_val by fastforce
hence vs: "Rval vs = Rval (y # vs')"
using cons_val by fastforce
from e obtain s' where "evaluate env s e (s', Rval y)"
using cons_val by fastforce
from e ys obtain s'' where "evaluate_list (evaluate env) s' es (s'', Rval vs')"
using cons_val by fastforce
show ?case
unfolding vs
by (rule; rule evaluate_list.cons1) fact+
qed (auto intro:evaluate_list.intros)
private lemma cupcake_list_correct_rerr:
assumes "list_all2_shortcircuit
(λe r.
cupcake_evaluate_single env e r ∧
(is_cupcake_all_env env ⟶ is_cupcake_exp e ⟶ (∀(s::'a state). ∃s'. evaluate env s e (s', r))))
es rs" "is_cupcake_all_env env" "list_all is_cupcake_exp es" "sequence_result rs = Rerr err"
shows " ∃s'. evaluate_list (evaluate env) (s::'a state) es (s',Rerr err)"
using assms proof (induction es rs arbitrary: s err rule:list_all2_shortcircuit_induct)
case (cons_val e es y ys)
then have "is_cupcake_exp e" "list_all is_cupcake_exp es"
by fastforce+
moreover have err: "sequence_result ys = Rerr err"
using cons_val
by (cases "sequence_result ys") (auto simp: error_result.map_id)
ultimately show ?case
using cons3 cons_val
by fast
qed (auto intro:evaluate_list.intros)
private lemma cupcake_list_correct0:
assumes "list_all2_shortcircuit
(λe r.
cupcake_evaluate_single env e r ∧
(is_cupcake_all_env env ⟶ is_cupcake_exp e ⟶ (∀(s::'a state). ∃s'. evaluate env s e (s', r))))
es rs" "is_cupcake_all_env env" "list_all is_cupcake_exp es"
shows " ∃s'. evaluate_list (evaluate env) (s::'a state) es (s',sequence_result rs)"
using assms by (cases "sequence_result rs") (fastforce intro: cupcake_list_correct_rval cupcake_list_correct_rerr)+
lemma cupcake_single_correct:
assumes "cupcake_evaluate_single env e res" "is_cupcake_all_env env" "is_cupcake_exp e"
shows "∃s'. Big_Step_Unclocked_Single.evaluate env s e (s',res)"
using assms proof (induction arbitrary:s rule:cupcake_evaluate_single.induct)
case (con1 env cn es rs vs v0)
then have "list_all is_cupcake_exp (rev es)"
by (cases rule: is_cupcake_exp.cases[where x = "Con cn es"]) auto
then show ?case
using cupcake_list_correct_rval evaluate.con1 con1
by blast
next
case (con3 env cn es rs err)
then have "list_all is_cupcake_exp (rev es)"
by (cases rule: is_cupcake_exp.cases[where x = "Con cn es"]) auto
then show ?case
using cupcake_list_correct_rerr con3 evaluate.con3
by blast
next
case (app1 env es rs vs env' e bv)
hence es: "list_all is_cupcake_exp (rev es)"
by fastforce
hence "list_all is_cupcake_value (rev vs)"
using app1 cupcake_list_preserve list_all2_shortcircuit_weaken
by (metis (no_types, lifting) list_all_rev)
hence "is_cupcake_exp e" and "is_cupcake_all_env env'"
using app1 cupcake_opapp_preserve by blast+
then show ?case
using cupcake_list_correct_rval es app1 evaluate.app1
by blast
next
case (app3 env es rs vs)
hence "list_all is_cupcake_exp (rev es)"
by simp
then show ?case
using cupcake_list_correct_rval evaluate.app3 app3
by blast
next
case (app6 env es rs err op0)
hence "list_all is_cupcake_exp (rev es)"
by simp
then show ?case
using cupcake_list_correct_rerr app6 evaluate.app6
by blast
next
case (mat1 env e v0 pes e' uu env' bv)
hence e: "is_cupcake_exp e" and "cupcake_c_ns (c env)" and pes: "cupcake_clauses pes" and "is_cupcake_value v0"
by (fastforce dest: is_cupcake_all_envD cupcake_single_preserve)+
hence "list_all (is_cupcake_value ∘ snd) env'" and e': "is_cupcake_exp e'"
using cupcake_match_result_preserve[where envC = "c env" and v = v0 and pes = pes and err_v = Bindv, unfolded mat1, simplified]
by blast+
have env': "is_cupcake_all_env (update_v (λ_. nsAppend (alist_to_ns env') (sem_env.v env)) env)"
apply (rule cupcake_v_update_preserve)
apply fact
apply (rule cupcake_nsAppend_preserve)
apply (rule cupcake_alist_to_ns_preserve)
apply fact
apply (rule is_cupcake_all_envD)
apply fact
done
from e obtain s' where "evaluate env s e (s', Rval v0)"
using mat1 by blast
have "match_result env s' v0 pes Bindv = Rval (e', env')"
using mat1 cupcake_match_result_eq[OF pes, where env = env and v = v0 and err_v = Bindv and s = s']
by fastforce
from e' env' obtain s'' where "evaluate (update_v (λ_. nsAppend (alist_to_ns env') (sem_env.v env)) env) s' e' (s'', bv)"
using mat1 by blast
show ?case
by rule+ fact+
next
case (mat1error env e v0 pes err)
hence "is_cupcake_exp e" and pes: "cupcake_clauses pes"
by (auto dest: is_cupcake_all_envD)
then obtain s' where "Big_Step_Unclocked_Single.evaluate env s e (s', Rval v0)"
using mat1error by blast
hence "match_result env s' v0 pes Bindv = Rerr err"
using cupcake_match_result_eq[OF pes, where env = env and s = s' and v = v0 and err_v = Bindv] unfolding mat1error
by (simp add: error_result.map_id)
show ?case
by (rule; rule evaluate.mat1b) fact+
next
case (mat2 _ e)
hence "is_cupcake_exp e"
by simp
then show ?case
using mat2 evaluate.mat2 by blast
qed (blast intro:evaluate.intros)+
lemma cupcake_list_correct:
assumes "list_all2_shortcircuit (cupcake_evaluate_single env) es rs" "is_cupcake_all_env env" "list_all is_cupcake_exp es"
shows " ∃s'. evaluate_list (evaluate env) (s::'a state) es (s',sequence_result rs)"
using assms by (fastforce intro:cupcake_list_correct0 list_all2_shortcircuit_weaken cupcake_single_correct)+
private lemma cupcake_list_complete0:
"evaluate_list
(λs e r. evaluate env s e r ∧ (is_cupcake_all_env env ⟶ is_cupcake_exp e ⟶ cupcake_evaluate_single env e (snd r))) s1 es res ⟹
is_cupcake_all_env env ⟹ list_all is_cupcake_exp es ⟹ ∃rs. list_all2_shortcircuit (cupcake_evaluate_single env) es rs ∧ sequence_result rs = (snd res)"
proof (induction rule:evaluate_list.induct)
case empty
have "list_all2_shortcircuit (cupcake_evaluate_single env) [] []"
by fastforce
then show ?case
by fastforce
next
case (cons1 s1 e s2 v es s3 vs)
then obtain rs where "list_all2_shortcircuit (cupcake_evaluate_single env) es rs"
and "sequence_result rs = Rval vs"
and "list_all2_shortcircuit (cupcake_evaluate_single env) (e # es) (Rval v # rs)"
by fastforce+
then show ?case
by fastforce
next
case (cons2 s1 e s2 err es)
hence "list_all2_shortcircuit (cupcake_evaluate_single env) (e # es) [Rerr err]"
by simp
then show ?case
by fastforce
next
case (cons3 s1 e s2 v es s3 err)
then obtain rs where "list_all2_shortcircuit (cupcake_evaluate_single env) es rs"
and err:"sequence_result rs = Rerr err"
and "list_all2_shortcircuit (cupcake_evaluate_single env) (e # es) (Rval v # rs)"
by fastforce
moreover have "sequence_result (Rval v # rs) = Rerr err"
by (auto simp: error_result.map_id err)
ultimately show ?case
by fastforce
qed
private lemma cupcake_single_complete0:
"evaluate env s e res ⟹ is_cupcake_all_env env ⟹ is_cupcake_exp e ⟹ cupcake_evaluate_single env e (snd res)"
proof (induction rule:evaluate.induct)
case (con1 env cn es vs v s1 s2)
hence "list_all is_cupcake_exp (rev es)"
by (cases rule: is_cupcake_exp.cases[where x = "Con cn es"]) auto
hence "list_all2_shortcircuit (cupcake_evaluate_single env) (rev es) (map Rval vs)"
using cupcake_list_complete0 con1 by fastforce
show ?case
by (simp|rule|fact)+
next
case (con3 env cn es s1 s2 err)
hence "list_all is_cupcake_exp (rev es)"
by (cases rule: is_cupcake_exp.cases[where x = "Con cn es"]) auto
then obtain rs where "list_all2_shortcircuit (cupcake_evaluate_single env) (rev es) rs" "sequence_result rs = Rerr err"
using con3 by (fastforce dest:cupcake_list_complete0)
show ?case
by (simp;rule cupcake_evaluate_single.con3) fact+
next
case (app1 env s1 es s2 vs env' e bv)
then obtain rs where rs: "list_all2_shortcircuit (cupcake_evaluate_single env) (rev es) rs" "sequence_result rs = Rval vs"
by (fastforce dest:cupcake_list_complete0)
hence "list_all is_cupcake_exp (rev es)"
using app1 by fastforce
hence "list_all is_cupcake_value vs" "list_all is_cupcake_value (rev vs)"
using cupcake_list_preserve app1 rs by fastforce+
hence "is_cupcake_exp e" "is_cupcake_all_env env'"
using app1 cupcake_opapp_preserve by fastforce+
hence "cupcake_evaluate_single env' e (snd bv)"
using app1 by fastforce
show ?case
by rule fact+
next
case (app3 env s1 es s2 vs)
hence "list_all is_cupcake_exp (rev es)"
by simp
obtain rs where " list_all2_shortcircuit (cupcake_evaluate_single env) (rev es) rs" "sequence_result rs = Rval vs"
using app3 cupcake_list_complete0 by fastforce
show ?case
by (simp|rule|fact)+
next
case (app6 env s1 es s2 err op0)
obtain rs where " list_all2_shortcircuit (cupcake_evaluate_single env) (rev es) rs" "sequence_result rs = Rerr err"
using cupcake_list_complete0 app6 by fastforce
show ?case
by (simp|rule|fact)+
next
case (mat1 env s1 e s2 v1 pes e' env' bv)
hence "is_cupcake_exp e" and "cupcake_c_ns (c env)" and pes:"cupcake_clauses pes" and "is_cupcake_value v1"
by (fastforce dest: is_cupcake_all_envD cupcake_single_preserve)+
moreover obtain uu where "cupcake_match_result (c env) v1 pes Bindv = Rval (e', uu, env')"
using cupcake_match_result_eq[OF pes,where env = env and s= s2 and v = v1 and err_v = Bindv, unfolded mat1]
by (cases "cupcake_match_result (c env) v1 pes Bindv") auto
ultimately have "list_all (is_cupcake_value ∘ snd) env'" "is_cupcake_exp e'"
using cupcake_match_result_preserve[where envC = "c env" and v = v1 and pes = pes and err_v = Bindv]
by fastforce+
moreover have "is_cupcake_all_env (update_v (λ_. nsAppend (alist_to_ns env') (sem_env.v env)) env)"
apply (rule cupcake_v_update_preserve)
apply fact
apply (rule cupcake_nsAppend_preserve)
apply (rule cupcake_alist_to_ns_preserve)
apply fact
apply (rule is_cupcake_all_envD)
apply fact
done
ultimately have "cupcake_evaluate_single env e (Rval v1)"
and "cupcake_evaluate_single (update_v (λ_. nsAppend (alist_to_ns env') (sem_env.v env)) env) e' (snd bv)"
using mat1 by fastforce+
show ?case
by (rule cupcake_evaluate_single.mat1) fact+
next
case (mat1b env s1 e s2 v1 pes err)
hence "is_cupcake_exp e" and pes: "cupcake_clauses pes"
by (auto dest: is_cupcake_all_envD)
have "cupcake_evaluate_single env e (Rval v1)"
using mat1b by fastforce
have "cupcake_match_result (c env) v1 pes Bindv = Rerr err"
using cupcake_match_result_eq[OF pes, where env = env and s = s2 and v = v1 and err_v = Bindv] unfolding mat1b
by (cases "(cupcake_match_result (c env) v1 pes Bindv)") (auto simp:error_result.map_id)
show ?case
by (simp; rule cupcake_evaluate_single.mat1error) fact+
qed (fastforce intro: cupcake_evaluate_single.intros)+
lemma cupcake_single_complete:
"evaluate env s e (s', res) ⟹ is_cupcake_all_env env ⟹ is_cupcake_exp e ⟹ cupcake_evaluate_single env e res"
by (fastforce dest:cupcake_single_complete0)
lemma cupcake_list_complete:
"evaluate_list (evaluate env) s1 es res ⟹
is_cupcake_all_env env ⟹ list_all is_cupcake_exp es ⟹ ∃rs. list_all2_shortcircuit (cupcake_evaluate_single env) es rs ∧ sequence_result rs = (snd res)"
by (fastforce intro:cupcake_list_complete0 cupcake_single_complete evaluate_list_mono_strong)
private lemma cupcake_list_state_preserve0:
assumes "evaluate_list (λs e res. Big_Step_Unclocked_Single.evaluate env s e res ∧ (is_cupcake_all_env env ⟶ is_cupcake_exp e ⟶ s = fst res)) s es res"
"list_all is_cupcake_exp es" "is_cupcake_all_env env"
shows "s = (fst res)"
using assms by (induction rule:evaluate_list.induct) auto
lemma cupcake_state_preserve:
assumes "Big_Step_Unclocked_Single.evaluate env s e res" "is_cupcake_all_env env" "is_cupcake_exp e"
shows "s = (fst res)"
using assms proof (induction arbitrary: rule: evaluate.induct)
case (con1 env cn es vs v s1 s2)
hence "list_all is_cupcake_exp es"
by (cases rule: is_cupcake_exp.cases[where x = "Con cn es"]) auto
then show ?case
using con1 by (fastforce dest:cupcake_list_state_preserve0)
next
case (con3 env cn es s1 s2 err)
hence "list_all is_cupcake_exp es"
by (cases rule: is_cupcake_exp.cases[where x = "Con cn es"]) auto
then show ?case
using con3 by (fastforce dest:cupcake_list_state_preserve0)
next
case (app1 env s1 es s2 vs env' e bv)
have "list_all is_cupcake_exp (rev es)"
using app1 by fastforce
then obtain rs where rs: "list_all2_shortcircuit (cupcake_evaluate_single env) (rev es) rs" "sequence_result rs = Rval vs"
using app1 by (fastforce dest:evaluate_list_mono_strong[THEN cupcake_list_complete])
hence "list_all is_cupcake_value vs" "list_all is_cupcake_value (rev vs)"
using cupcake_list_preserve app1 rs by fastforce+
hence "is_cupcake_exp e" "is_cupcake_all_env env'"
using app1 cupcake_opapp_preserve by fastforce+
then show ?case
using app1 by (fastforce dest:cupcake_list_state_preserve0)
next
case (mat1 env s1 e s2 v1 pes e' env' bv)
hence "is_cupcake_exp e" and "cupcake_c_ns (c env)" and pes:"cupcake_clauses pes" and "is_cupcake_value v1"
by (fastforce dest: is_cupcake_all_envD cupcake_single_complete cupcake_single_preserve)+
moreover obtain uu where "cupcake_match_result (c env) v1 pes Bindv = Rval (e', uu, env')"
using cupcake_match_result_eq[OF pes,where env = env and s= s2 and v = v1 and err_v = Bindv, unfolded mat1]
by (cases "cupcake_match_result (c env) v1 pes Bindv") auto
ultimately have "list_all (is_cupcake_value ∘ snd) env'" "is_cupcake_exp e'"
using cupcake_match_result_preserve[where envC = "c env" and v = v1 and pes = pes and err_v = Bindv]
by fastforce+
moreover have "is_cupcake_all_env (update_v (λ_. nsAppend (alist_to_ns env') (sem_env.v env)) env)"
apply (rule cupcake_v_update_preserve)
apply fact
apply (rule cupcake_nsAppend_preserve)
apply (rule cupcake_alist_to_ns_preserve)
apply fact
apply (rule is_cupcake_all_envD)
apply fact
done
ultimately show ?case
using mat1 by fastforce
qed (fastforce dest:cupcake_list_state_preserve0)+
corollary cupcake_single_correct_strong:
assumes "cupcake_evaluate_single env e res" "is_cupcake_all_env env" "is_cupcake_exp e"
shows "Big_Step_Unclocked_Single.evaluate env s e (s,res)"
using assms cupcake_single_correct cupcake_state_preserve by fastforce
corollary cupcake_single_complete_weak:
"evaluate env s e (s, res) ⟹ is_cupcake_all_env env ⟹ is_cupcake_exp e ⟹ cupcake_evaluate_single env e res"
using cupcake_single_complete by fastforce
end end
hide_const (open) c
end