theory ExCF imports HOLCF HOLCFUtils CPSScheme Utils begin
text‹
now alter the standard semantics given in the previous section to calculate a control flow graph instead of the return value. At this point, we still ``run'' the program in full, so this is not yet the static analysis that we aim for. Instead, this is the reference for the correctness proof of the static analysis: If an edge is recorded here, we expect it to be found by the static analysis as well. ›
text‹
preparation of the correctness proof we change the type of the contour counters. Instead of plain natural numbers as in the previous sections we use lists of labels, remembering at each step which part of the program was just evaluated.
that for the exact semantics, this is information is not used in any way and it would have been possible to just use natural numbers again. This is reflected by the preorder instance for the contours which only look at the length of the list, but not the entries. ›
definition"contour = (UNIV::label list set)"
typedef contour = contour unfolding contour_def by auto
definition nb where"nb b c = Abs_contour (c # Rep_contour b)"
instantiation contour :: preorder begin definition le_contour_def: "b ≤ b' ⟷ length (Rep_contour b) ≤ length (Rep_contour b')" definition less_contour_def: "b < b' ⟷ length (Rep_contour b) < length (Rep_contour b')" instanceproof qed(auto simp add:le_contour_def less_contour_def Rep_contour_inverse Abs_contour_inverse contour_def) end
text‹
simple lemmas helping Isabelle to automatically prove statements about contour numbers. ›
lemma nb_le_less[iff]: "nb b c ≤ b' ⟷ b < b'" unfolding nb_def by (auto simp add:le_contour_def less_contour_def Rep_contour_inverse Abs_contour_inverse contour_def)
lemma nb_less[iff]: "b' < nb b c ⟷ b' ≤ b" unfolding nb_def by (auto simp add:le_contour_def less_contour_def Rep_contour_inverse Abs_contour_inverse contour_def)
declare less_imp_le[where 'a = contour, intro]
text‹
other types used in our semantics functions have not changed. ›
text‹
please @{theory HOLCF}, we declare the discrete partial order for our types: ›
instantiation contour :: discrete_cpo begin definition [simp]: "(x::contour) ⊑ y ⟷ x = y" instanceby standard simp end instantiation d :: discrete_cpo begin definition [simp]: "(x::d) ⊑ y ⟷ x = y" instanceby standard simp end
instantiation call :: discrete_cpo begin definition [simp]: "(x::call) ⊑ y ⟷ x = y" instanceby standard simp end
text‹
evaluation function for values has only changed slightly: To avoid worrying about incorrect programs, we return zero when a variable lookup fails. If the labels in the program given are correct, this will not happen. Shivers makes this explicit in Section 4.1.3 by restricting the function domains to the valid programs. This is omitted here. ›
fun evalV :: "val ==> benv ==> venv ==> d" (‹A›) where"A (C _ i) β ve = DI i"
| "A (P prim) β ve = DP prim"
| "A (R _ var) β ve = (case β (binder var) of Some l ==> (case ve (var,l) of Some d ==> d | None ==> DI 0) | None ==> DI 0)"
| "A (L lam) β ve = DC (lam, β)"
text‹
be able to do case analysis on the custom datatypes ‹lambda›, ‹d›, ‹call› and ‹prim› inside a function defined with ‹fixrec›, we need continuity results for them. These are all of the same shape and proven by case analysis on the discriminator. ›
lemma cont2cont_case_lambda [simp, cont2cont]: assumes"∧a b c. cont (λx. f x a b c)" shows"cont (λx. case_lambda (f x) l)" using assms by (cases l) auto
lemma cont2cont_case_d [simp, cont2cont]: assumes"∧y. cont (λx. f1 x y)" and"∧y. cont (λx. f2 x y)" and"∧y. cont (λx. f3 x y)" and"cont (λx. f4 x)" shows"cont (λx. case_d (f1 x) (f2 x) (f3 x) (f4 x) d)" using assms by (cases d) auto
lemma cont2cont_case_call [simp, cont2cont]: assumes"∧a b c. cont (λx. f1 x a b c)" and"∧a b c. cont (λx. f2 x a b c)" shows"cont (λx. case_call (f1 x) (f2 x) c)" using assms by (cases c) auto
lemma cont2cont_case_prim [simp, cont2cont]: assumes"∧y. cont (λx. f1 x y)" and"∧y z. cont (λx. f2 x y z)" shows"cont (λx. case_prim (f1 x) (f2 x) p)" using assms by (cases p) auto
text‹
, our answer domain is not any more the integers, but rather call caches. These are represented as sets containing tuples of call sites (given by their label) and binding environments to the called value. The argument types are unaltered.
the functions ‹F› and ‹C›, upon every call, a new element is added to the resulting set. The ‹STOP› continuation now ignores its argument and retuns the empty set instead. This corresponds to Figure 4.2 and 4.3 in Shivers' dissertation. ›
fixrec evalF :: "fstate discr → ans" (‹F›) and evalC :: "cstate discr → ans" (‹C›) where"F⋅fstate = (case undiscr fstate of (DC (Lambda lab vs c, β), as, ve, b) ==> (if length vs = length as then let β' = β (lab ↦ b); ve' = map_upds ve (map (λv.(v,b)) vs) as in C⋅(Discr (c,β',ve',b)) else ⊥) | (DP (Plus c),[DI a1, DI a2, cnt],ve,b) ==> (if isProc cnt then let b' = nb b c; β = [c ↦ b] in F⋅(Discr (cnt,[DI (a1 + a2)],ve,b')) ∪ {((c, β),cnt)} else ⊥) | (DP (prim.If ct cf),[DI v, contt, contf],ve,b) ==> (if isProc contt ∧ isProc contf then (if v ≠ 0 then let b' = nb b ct; β = [ct ↦ b] in (F⋅(Discr (contt,[],ve,b')) ∪ {((ct, β),contt)}) else let b' = nb b cf; β = [cf ↦ b] in (F⋅(Discr (contf,[],ve,b'))) ∪ {((cf, β),contf)}) else ⊥) | (Stop,[DI i],_,_) ==> {} | _ ==>⊥ )"
| "C⋅cstate = (case undiscr cstate of (App lab f vs,β,ve,b) ==> let f' = A f β ve; as = map (λv. A v β ve) vs; b' = nb b lab in if isProc f' then F⋅(Discr (f',as,ve,b')) ∪ {((lab, β),f')} else ⊥ | (Let lab ls c',β,ve,b) ==> let b' = nb b lab; β' = β (lab ↦ b'); ve' = ve ++ map_of (map (λ(v,l). ((v,b'), A (L l) β' ve)) ls) in C⋅(Discr (c',β',ve',b')) )"
text‹
preparation of later proofs, we give the cases of the generated induction rule names and also create a large rule to deconstruct the an value of type ‹fstate› into the various cases that were used in the definition of ‹F›. ›
lemmas cl_cases = prod.exhaust[OF lambda.exhaust, of _ "λ a _ . a"] lemmas ds_cases_plus = list.exhaust[
OF _ d.exhaust, of _ _ "λa _. a",
OF _ list.exhaust, of _ _ "λ_ x _. x",
OF _ _ d.exhaust, of _ _ "λ_ _ _ a _. a",
OF _ _ list.exhaust,of _ _ "λ_ _ _ _ x _. x",
OF _ _ _ list.exhaust,of _ _ "λ_ _ _ _ _ _ _ x. x"
] lemmas ds_cases_if = list.exhaust[OF _ d.exhaust, of _ _ "λa _. a",
OF _ list.exhaust[OF _ list.exhaust[OF _ list.exhaust, of _ _ "λ_ x. x"], of _ _ "λ_ x. x"], of _ _ "λ_ x _. x"] lemmas ds_cases_stop = list.exhaust[OF _ d.exhaust, of _ _ "λa _. a",
OF _ list.exhaust, of _ _ "λ_ x _. x"] lemmas fstate_case = prod_cases4[OF d.exhaust, of _ "λx _ _ _ . x",
OF _ cl_cases prim.exhaust, of _ _ "λ _ _ _ _ a . a""λ _ _ _ _ a. a",
OF _ case_split ds_cases_plus ds_cases_if ds_cases_stop,
of _ _ "λ_ as _ _ _ _ _ _ vs _ . length vs = length as""λ _ ds _ _ _ _ . ds""λ _ ds _ _ _ _ _. ds""λ _ ds _ _. ds",
case_names "x""Closure""x""x""x""x""Plus""x""x""x""x""x""x""x""x""x""x""If_True""If_False""x""x""x""x""x""Stop""x""x""x""x""x"]
text‹
exact semantics of a program again uses ‹F› with properly initialized arguments. For the first two examples, we see that the function works as expected. ›
definition evalCPS :: "prog ==> ans" (‹🚫›) where"🚫 l = (let ve = Map.empty; β = Map.empty; f = A (L l) β ve in F⋅(Discr (f,[Stop],ve,🚫)))"
¤ Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.0.15Bemerkung:
(vorverarbeitet am 2026-06-10)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.