Theory Rhombus_HOL_Code_API
theory Rhombus_HOL_Code_API
imports "../verification/Rhombus_HOL_Audit" "../extensions/Rhombus_HOL_Nat_Extension"
begin
section ‹Finite code-generation façade›
type_synonym type_subst_entries = "(hname × htype) list"
definition entries_subst :: "type_subst_entries ⇒ hname ⇒ htype option" where
"entries_subst entries = map_of entries"
definition valid_type_subst_entries ::
"htheory ⇒ type_subst_entries ⇒ bool" where
"valid_type_subst_entries thy entries ⟷
distinct (map fst entries) ∧ list_all (check_type thy ∘ snd) entries"
lemma valid_type_subst_entries_lookup:
assumes "valid_type_subst_entries thy entries"
"entries_subst entries n = Some ty"
shows "check_type thy ty"
using assms map_of_SomeD
by (auto simp: valid_type_subst_entries_def entries_subst_def list_all_iff)
lemma valid_type_subst_entries_preserve_type:
assumes valid: "valid_type_subst_entries thy entries"
and checked: "check_type thy ty"
shows "check_type thy (type_subst (entries_subst entries) ty)"
using checked
proof (induction ty)
case (TyVar n)
then show ?case
using valid valid_type_subst_entries_lookup
by (auto split: option.splits)
next
case (TyApp n args)
then show ?case by (auto simp: list_all_iff)
qed
definition subst_option_map ::
"(hname ⇒ htype option) ⇒ (hname ⇒ htype option) ⇒ hname ⇒ htype option" where
"subst_option_map σ θ n = map_option (type_subst σ) (θ n)"
lemma type_subst_option_map:
assumes "∀n. type_var_occurs n ty ⟶ θ n ≠ None"
shows "type_subst (subst_option_map σ θ) ty = type_subst σ (type_subst θ ty)"
using assms
proof (induction ty)
case (TyVar n)
then show ?case by (cases "θ n") (auto simp: subst_option_map_def)
next
case (TyApp n args)
have each: "⋀arg. arg ∈ set args ⟹
∀v. type_var_occurs v arg ⟶ θ v ≠ None"
using TyApp.prems by (auto simp: list_ex_iff)
have args_eq: "map (type_subst (subst_option_map σ θ)) args =
map (type_subst σ ∘ type_subst θ) args"
proof (rule map_cong)
fix arg
assume arg: "arg ∈ set args"
show "type_subst (subst_option_map σ θ) arg =
(type_subst σ ∘ type_subst θ) arg"
using TyApp.IH[OF arg each[OF arg]] by simp
qed simp
then show ?case by (simp only: type_subst.simps map_map o_apply)
qed
lemma fold_type_match_fuel_none [simp]:
"fold (λ(p, t) result.
case result of None ⇒ None | Some acc ⇒ type_match_fuel k p t acc)
pairs None = None"
by (induction pairs) auto
lemma fold_type_match_fuel_subst:
assumes step: "⋀p t acc out. (p, t) ∈ set pairs ⟹
type_match_fuel k p t acc = Some out ⟹
type_match_fuel k p (type_subst σ t) (subst_option_map σ acc) =
Some (subst_option_map σ out)"
and run: "fold (λ(p, t) result.
case result of None ⇒ None | Some acc ⇒ type_match_fuel k p t acc)
pairs (Some acc) = Some out"
shows "fold (λ(p, t) result.
case result of None ⇒ None | Some acc ⇒ type_match_fuel k p t acc)
(map (λ(p, t). (p, type_subst σ t)) pairs)
(Some (subst_option_map σ acc)) = Some (subst_option_map σ out)"
using run step
proof (induction pairs arbitrary: acc out)
case Nil
then show ?case by simp
next
case (Cons pair pairs)
obtain p t where pair: "pair = (p, t)" by (cases pair)
show ?case
proof (cases "type_match_fuel k p t acc")
case None
then show ?thesis using Cons.prems pair by simp
next
case (Some mid)
have first: "type_match_fuel k p (type_subst σ t)
(subst_option_map σ acc) = Some (subst_option_map σ mid)"
using Cons.prems(2)[of p t acc mid] Some pair by simp
have rest: "fold (λ(p, t) result.
case result of None ⇒ None | Some acc ⇒ type_match_fuel k p t acc)
pairs (Some mid) = Some out"
using Cons.prems(1) Some pair by simp
have rest_step: "⋀p t acc out. (p, t) ∈ set pairs ⟹
type_match_fuel k p t acc = Some out ⟹
type_match_fuel k p (type_subst σ t) (subst_option_map σ acc) =
Some (subst_option_map σ out)"
using Cons.prems(2) pair by auto
show ?thesis using Cons.IH[OF rest rest_step] first pair by simp
qed
qed
lemma type_match_fuel_subst:
assumes "type_match_fuel k pat ty acc = Some out"
shows "type_match_fuel k pat (type_subst σ ty) (subst_option_map σ acc) =
Some (subst_option_map σ out)"
using assms
proof (induction k pat ty acc arbitrary: out rule: type_match_fuel.induct)
case (3 k n ps m ts acc)
show ?case
proof (cases "n = m ∧ length ps = length ts")
case False
have False using 3 False by (auto split: if_splits)
then show ?thesis by blast
next
case True
have run: "fold (λ(p, t) result.
case result of None ⇒ None | Some acc ⇒ type_match_fuel k p t acc)
(zip ps ts) (Some acc) = Some out"
using 3 True by (auto split: if_splits)
have step: "⋀p t acc out. (p, t) ∈ set (zip ps ts) ⟹
type_match_fuel k p t acc = Some out ⟹
type_match_fuel k p (type_subst σ t) (subst_option_map σ acc) =
Some (subst_option_map σ out)"
proof -
fix p t acc' out'
assume mem: "(p, t) ∈ set (zip ps ts)"
and subrun: "type_match_fuel k p t acc' = Some out'"
show "type_match_fuel k p (type_subst σ t) (subst_option_map σ acc') =
Some (subst_option_map σ out')"
using 3(1)[OF True mem refl subrun] .
qed
have transformed: "fold (λ(p, t) result.
case result of None ⇒ None | Some acc ⇒ type_match_fuel k p t acc)
(map (λ(p, t). (p, type_subst σ t)) (zip ps ts))
(Some (subst_option_map σ acc)) = Some (subst_option_map σ out)"
using fold_type_match_fuel_subst[OF step run] .
show ?thesis using transformed True
by (simp add: zip_map2)
qed
qed (auto simp: subst_option_map_def split: htype.splits option.splits if_splits)
lemma fold_type_match_fuel_invariant:
fixes pairs :: "(htype × htype) list"
assumes step_preserves: "⋀p t acc out. (p, t) ∈ set pairs ⟹
type_match_fuel k p t acc = Some out ⟹ acc v ≠ None ⟹ out v = acc v"
and step_covers: "⋀p t acc out. (p, t) ∈ set pairs ⟹
type_match_fuel k p t acc = Some out ⟹ type_var_occurs v p ⟹ out v ≠ None"
and run: "fold (λ(p, t) result.
case result of None ⇒ None | Some acc ⇒ type_match_fuel k p t acc)
pairs (Some acc) = Some out"
shows "(acc v ≠ None ⟶ out v = acc v) ∧
(list_ex (λ(p, t). type_var_occurs v p) pairs ⟶ out v ≠ None)"
using step_preserves step_covers run
proof (induction pairs arbitrary: acc out)
case Nil
then show ?case by simp
next
case (Cons pair pairs)
obtain p t where pair: "pair = (p, t)" by (cases pair)
obtain mid where first: "type_match_fuel k p t acc = Some mid"
and rest: "fold (λ(p, t) result.
case result of None ⇒ None | Some acc ⇒ type_match_fuel k p t acc)
pairs (Some mid) = Some out"
using Cons.prems(3) unfolding pair
by (cases "type_match_fuel k p t acc") auto
have head_mem: "(p, t) ∈ set (pair # pairs)" unfolding pair by simp
have head_preserves: "acc v ≠ None ⟹ mid v = acc v"
using Cons.prems(1)[OF head_mem first] .
have head_covers: "type_var_occurs v p ⟹ mid v ≠ None"
using Cons.prems(2)[OF head_mem first] .
have tail_preserves: "⋀p t acc out. (p, t) ∈ set pairs ⟹
type_match_fuel k p t acc = Some out ⟹ acc v ≠ None ⟹ out v = acc v"
proof -
fix p t acc' out'
assume mem: "(p, t) ∈ set pairs"
and subrun: "type_match_fuel k p t acc' = Some out'"
and present: "acc' v ≠ None"
have "(p, t) ∈ set (pair # pairs)" using mem by simp
then show "out' v = acc' v"
using Cons.prems(1) subrun present by blast
qed
have tail_covers: "⋀p t acc out. (p, t) ∈ set pairs ⟹
type_match_fuel k p t acc = Some out ⟹ type_var_occurs v p ⟹ out v ≠ None"
proof -
fix p t acc' out'
assume mem: "(p, t) ∈ set pairs"
and subrun: "type_match_fuel k p t acc' = Some out'"
and occurs: "type_var_occurs v p"
have "(p, t) ∈ set (pair # pairs)" using mem by simp
then show "out' v ≠ None"
using Cons.prems(2) subrun occurs by blast
qed
have tail: "(mid v ≠ None ⟶ out v = mid v) ∧
(list_ex (λ(p, t). type_var_occurs v p) pairs ⟶ out v ≠ None)"
proof (rule Cons.IH)
show "⋀p t acc out. (p, t) ∈ set pairs ⟹
type_match_fuel k p t acc = Some out ⟹ acc v ≠ None ⟹ out v = acc v"
by (rule tail_preserves)
show "⋀p t acc out. (p, t) ∈ set pairs ⟹
type_match_fuel k p t acc = Some out ⟹ type_var_occurs v p ⟹ out v ≠ None"
by (rule tail_covers)
show "fold (λ(p, t) result.
case result of None ⇒ None | Some acc ⇒ type_match_fuel k p t acc)
pairs (Some mid) = Some out" by (rule rest)
qed
show ?case using head_preserves head_covers tail unfolding pair by auto
qed
lemma type_match_fuel_invariant:
assumes "type_match_fuel k pat ty acc = Some out"
shows "(acc v ≠ None ⟶ out v = acc v) ∧
(type_var_occurs v pat ⟶ out v ≠ None)"
using assms
proof (induction k pat ty acc arbitrary: out rule: type_match_fuel.induct)
case (3 k n ps m ts acc)
show ?case
proof (cases "n = m ∧ length ps = length ts")
case False
have False using 3 False by (auto split: if_splits)
then show ?thesis by blast
next
case True
have run: "fold (λ(p, t) result.
case result of None ⇒ None | Some acc ⇒ type_match_fuel k p t acc)
(zip ps ts) (Some acc) = Some out"
using 3 True by (auto split: if_splits)
have step_preserves: "⋀p t acc out. (p, t) ∈ set (zip ps ts) ⟹
type_match_fuel k p t acc = Some out ⟹ acc v ≠ None ⟹ out v = acc v"
using 3(1)[OF True] by blast
have step_covers: "⋀p t acc out. (p, t) ∈ set (zip ps ts) ⟹
type_match_fuel k p t acc = Some out ⟹ type_var_occurs v p ⟹ out v ≠ None"
using 3(1)[OF True] by blast
have folded: "(acc v ≠ None ⟶ out v = acc v) ∧
(list_ex (λ(p, t). type_var_occurs v p) (zip ps ts) ⟶ out v ≠ None)"
using fold_type_match_fuel_invariant[OF step_preserves step_covers run] .
have zipped: "list_ex (type_var_occurs v) ps ⟹
list_ex (λ(p, t). type_var_occurs v p) (zip ps ts)"
using True
proof (induction ps arbitrary: ts)
case Nil
then show ?case by simp
next
case (Cons p ps)
then obtain t ts' where ts: "ts = t # ts'" by (cases ts) auto
show ?case
proof (cases "type_var_occurs v p")
case True
then show ?thesis unfolding ts by simp
next
case False
have tail_occurs: "list_ex (type_var_occurs v) ps"
using Cons.prems(1) False by simp
have tail_length: "n = m ∧ length ps = length ts'"
using Cons.prems(2) ts by simp
have tail_zipped: "list_ex (λ(p, t). type_var_occurs v p) (zip ps ts')"
using Cons.IH[OF tail_occurs tail_length] .
then show ?thesis unfolding ts by simp
qed
qed
show ?thesis using folded zipped by auto
qed
qed (auto simp: subst_option_map_def split: htype.splits option.splits if_splits)
lemma type_match_subst:
assumes match: "type_match pat ty (λ_. None) = Some out"
shows "type_match pat (type_subst σ ty) (λ_. None) =
Some (subst_option_map σ out)"
proof -
have run: "type_match_fuel (size pat + 1) pat ty (λ_. None) = Some out"
using match by (auto simp: type_match_def split: option.splits if_splits)
have covers: "∀v. type_var_occurs v pat ⟶ out v ≠ None"
using type_match_fuel_invariant[OF run] by blast
have composed: "type_subst (subst_option_map σ out) pat = type_subst σ ty"
using type_subst_option_map[OF covers] type_match_sound[OF match] by simp
have empty_map: "subst_option_map σ (λ_. None) = (λ_. None)"
by (rule ext) (simp add: subst_option_map_def)
have transformed: "type_match_fuel (size pat + 1) pat (type_subst σ ty)
(λ_. None) = Some (subst_option_map σ out)"
using type_match_fuel_subst[where σ = σ, OF run] empty_map by simp
show ?thesis unfolding type_match_def using transformed composed by simp
qed
lemma valid_type_subst_entries_type_subst_ok:
assumes valid: "valid_type_subst_entries thy entries"
shows "type_subst_ok thy (entries_subst entries)"
unfolding type_subst_ok_def
proof (intro conjI)
show "∀n ty. entries_subst entries n = Some ty ⟶ check_type thy ty"
using valid valid_type_subst_entries_lookup by blast
show "∀ty. check_type thy ty ⟶ check_type thy (type_subst (entries_subst entries) ty)"
using valid valid_type_subst_entries_preserve_type by blast
show "∀n ty. check_open_term thy [] (Const n ty) ⟶
check_open_term thy [] (Const n (type_subst (entries_subst entries) ty))"
proof (intro allI impI)
fix n ty
assume checked: "check_open_term thy [] (Const n ty)"
have checked_type: "check_type thy (type_subst (entries_subst entries) ty)"
using checked valid valid_type_subst_entries_preserve_type by simp
obtain generic where generic: "const_tab thy n = Some generic"
using checked by (cases "const_tab thy n") auto
obtain out where matched: "type_match generic ty (λ_. None) = Some out"
using checked generic by (cases "type_match generic ty (λ_. None)") auto
have substituted: "type_match generic (type_subst (entries_subst entries) ty) (λ_. None) =
Some (subst_option_map (entries_subst entries) out)"
using type_match_subst[OF matched] .
show "check_open_term thy [] (Const n (type_subst (entries_subst entries) ty))"
using checked_type generic substituted by simp
qed
qed
definition inst_type_entries ::
"htheory ⇒ type_subst_entries ⇒ hthm ⇒ hthm option" where
"inst_type_entries thy entries th =
(if valid_type_subst_entries thy entries ∧
descends (thm_stamp th) (thy_stamp thy) then
checked_thm thy
(rehash_hyps (map (inst_type (entries_subst entries)) (hyps th)))
(inst_type (entries_subst entries) (concl th)) (thy_stamp thy)
else None)"
lemma inst_type_entries_agrees:
assumes valid: "valid_type_subst_entries thy entries"
shows "inst_type_entries thy entries th =
inst_type_rule thy (entries_subst entries) th"
using valid valid_type_subst_entries_type_subst_ok[OF valid]
by (simp add: inst_type_entries_def inst_type_rule_def)
section ‹Direct code-generation rule façade›