Theory Pats
chapter ‹Wellformedness of patterns›
theory Pats
imports Term
begin
text ‹
The @{class term} class already defines a generic definition of ∗‹matching› a ∗‹pattern› with a
term. Importantly, the type of patterns is neither generic, nor a dedicated pattern type; instead,
it is @{typ term} itself.
Patterns are a proper subset of terms, with the restriction that no abstractions may occur and
there must be at most a single occurrence of any variable (usually known as ∗‹linearity›).
The first restriction can be modelled in a datatype, the second cannot. Consequently, I define a
predicate that captures both properties.
Using linearity, many more generic properties can be proved, for example that substituting the
environment produced by matching yields the matched term.
›
fun linear :: "term ⇒ bool" where
"linear (Free _) ⟷ True" |
"linear (Const _) ⟷ True" |
"linear (t⇩1 $ t⇩2) ⟷ linear t⇩1 ∧ linear t⇩2 ∧ ¬ is_free t⇩1 ∧ fdisjnt (frees t⇩1) (frees t⇩2)" |
"linear _ ⟷ False"
lemmas linear_simps[simp] =
linear.simps(2)[folded const_term_def]
linear.simps(3)[folded app_term_def]
lemma linear_implies_no_abs: "linear t ⟹ no_abs t"
proof induction
case Const
then show ?case
by (fold const_term_def free_term_def app_term_def) auto
next
case Free
then show ?case
by (fold const_term_def free_term_def app_term_def) auto
next
case App
then show ?case
by (fold const_term_def free_term_def app_term_def) auto
qed auto
fun linears :: "term list ⇒ bool" where
"linears [] ⟷ True" |
"linears (t # ts) ⟷ linear t ∧ fdisjnt (frees t) (freess ts) ∧ linears ts"
lemma linears_butlastI[intro]: "linears ts ⟹ linears (butlast ts)"
proof (induction ts)
case (Cons t ts)
hence "linear t" "linears (butlast ts)"
by simp+
moreover have " fdisjnt (frees t) (freess (butlast ts))"
proof (rule fdisjnt_subset_right)
show "freess (butlast ts) |⊆| freess ts"
by (rule freess_subset) (auto dest: in_set_butlastD)
next
show "fdisjnt (frees t) (freess ts)"
using Cons by simp
qed
ultimately show ?case
by simp
qed simp
lemma linears_appI[intro]:
assumes "linears xs" "linears ys" "fdisjnt (freess xs) (freess ys)"
shows "linears (xs @ ys)"
using assms proof (induction xs)
case (Cons z zs)
hence "linears zs"
by simp+
have "fdisjnt (frees z) (freess zs |∪| freess ys)"
proof (rule fdisjnt_union_right)
show "fdisjnt (frees z) (freess zs)"
using ‹linears (z # zs)› by simp
next
have "frees z |⊆| freess (z # zs)"
unfolding freess_def by simp
thus "fdisjnt (frees z) (freess ys)"
by (rule fdisjnt_subset_left) fact
qed
moreover have "linears (zs @ ys)"
proof (rule Cons)
show "fdisjnt (freess zs) (freess ys)"
using Cons
by (auto intro: freess_subset fdisjnt_subset_left)
qed fact+
ultimately show ?case
using Cons by auto
qed simp
lemma linears_linear: "linears ts ⟹ t ∈ set ts ⟹ linear t"
by (induct ts) auto
lemma linears_singleI[intro]: "linear t ⟹ linears [t]"
by (simp add: freess_def fdisjnt_alt_def)
lemma linear_strip_comb: "linear t ⟹ linear (fst (strip_comb t))"
by (induction t rule: strip_comb_induct) (auto simp: split_beta)
lemma linears_strip_comb: "linear t ⟹ linears (snd (strip_comb t))"
proof (induction t rule: strip_comb_induct)
case (app t⇩1 t⇩2)
have "linears (snd (strip_comb t⇩1) @ [t⇩2])"
proof (intro linears_appI linears_singleI)
have "freess (snd (strip_comb t⇩1)) |⊆| frees t⇩1"
by (subst frees_strip_comb) auto
moreover have "fdisjnt (frees t⇩1) (frees t⇩2)"
using app by auto
ultimately have "fdisjnt (freess (snd (strip_comb t⇩1))) (frees t⇩2)"
by (rule fdisjnt_subset_left)
thus "fdisjnt (freess (snd (strip_comb t⇩1))) (freess [t⇩2])"
by simp
next
show "linear t⇩2" "linears (snd (strip_comb t⇩1))"
using app by auto
qed
thus ?case
by (simp add: split_beta)
qed auto
lemma linears_appendD:
assumes "linears (xs @ ys)"
shows "linears xs" "linears ys" "fdisjnt (freess xs) (freess ys)"
using assms proof (induction xs)
case (Cons x xs)
assume "linears ((x # xs) @ ys)"
hence "linears (x # (xs @ ys))"
by simp
hence "linears (xs @ ys)" "linear x" "fdisjnt (frees x) (freess (xs @ ys))"
by auto
hence "linears xs"
using Cons by simp
moreover have "fdisjnt (frees x) (freess xs)"
proof (rule fdisjnt_subset_right)
show "freess xs |⊆| freess (xs @ ys)" by simp
qed fact
ultimately show "linears (x # xs)"
using ‹linear x› by auto
have "fdisjnt (freess xs) (freess ys)"
by (rule Cons) fact
moreover have "fdisjnt (frees x) (freess ys)"
proof (rule fdisjnt_subset_right)
show "freess ys |⊆| freess (xs @ ys)" by simp
qed fact
ultimately show "fdisjnt (freess (x # xs)) (freess ys)"
unfolding fdisjnt_alt_def
by auto
qed (auto simp: fdisjnt_alt_def)
lemma linear_list_comb:
assumes "linear f" "linears xs" "fdisjnt (frees f) (freess xs)" "¬ is_free f"
shows "linear (list_comb f xs)"
using assms
proof (induction xs arbitrary: f)
case (Cons x xs)
hence *: "fdisjnt (frees f) (frees x |∪| freess xs)"
by simp
have "linear (list_comb (f $ x) xs)"
proof (rule Cons)
have "linear x"
using Cons by simp
moreover have "fdisjnt (frees f) (frees x)"
using * by (auto intro: fdisjnt_subset_right)
ultimately show "linear (f $ x)"
using assms Cons by simp
next
show "linears xs"
using Cons by simp
next
have "fdisjnt (frees f) (freess xs)"
using * by (auto intro: fdisjnt_subset_right)
moreover have "fdisjnt (frees x) (freess xs)"
using Cons by simp
ultimately show "fdisjnt (frees (f $ x)) (freess xs)"
by (auto intro: fdisjnt_union_left)
qed auto
thus ?case
by (simp add: app_term_def)
qed auto
corollary linear_list_comb': "linears xs ⟹ linear (name $$ xs)"
by (auto intro: linear_list_comb simp: fdisjnt_alt_def)
lemma linear_strip_comb_cases[consumes 1]:
assumes "linear pat"
obtains (comb) s args where "strip_comb pat = (Const s, args)" "pat = s $$ args"
| (free) s where "strip_comb pat = (Free s, [])" "pat = Free s"
using assms
proof (induction pat rule: strip_comb_induct)
case (app t⇩1 t⇩2)
show ?case
proof (rule "app.IH")
show "linear t⇩1"
using app by simp
next
fix s
assume "strip_comb t⇩1 = (Free s, [])"
hence "t⇩1 = Free s"
by (metis fst_conv snd_conv strip_comb_empty)
hence False
using app by simp
thus thesis
by simp
next
fix s args
assume "strip_comb t⇩1 = (Const s, args)"
with app show thesis
by (fastforce simp add: strip_comb_app)
qed
next
case (no_app t)
thus ?case
by (cases t) (auto simp: const_term_def)
qed
lemma wellformed_linearI: "linear t ⟹ wellformed' n t"
by (induct t) auto
lemma pat_cases:
obtains (free) s where "t = Free s"
| (comb) name args where "linears args" "t = name $$ args"
| (nonlinear) "¬ linear t"
proof (cases t)
case Free
thus thesis using free by simp
next
case Bound
thus thesis using nonlinear by simp
next
case Abs
thus thesis using nonlinear by simp
next
case (Const name)
have "linears []" by simp
moreover have "t = name $$ []" unfolding Const by (simp add: const_term_def)
ultimately show thesis
by (rule comb)
next
case (App u v)
show thesis
proof (cases "linear t")
case False
thus thesis using nonlinear by simp
next
case True
thus thesis
proof (cases rule: linear_strip_comb_cases)
case free
thus thesis using that by simp
next
case (comb name args)
moreover hence "linears (snd (strip_comb t))"
using True by (blast intro: linears_strip_comb)
ultimately have "linears args"
by simp
thus thesis using that comb by simp
qed
qed
qed
corollary linear_pat_cases[consumes 1]:
assumes "linear t"
obtains (free) s where "t = Free s"
| (comb) name args where "linears args" "t = name $$ args"
using assms
by (metis pat_cases)
lemma linear_pat_induct[consumes 1, case_names free comb]:
assumes "linear t"
assumes "⋀s. P (Free s)"
assumes "⋀name args. linears args ⟹ (⋀arg. arg ∈ set args ⟹ P arg) ⟹ P (name $$ args)"
shows "P t"
using wf_measure[of size] ‹linear t›
proof (induction t)
case (less t)
show ?case
using ‹linear t›
proof (cases rule: linear_pat_cases)
case (free name)
thus ?thesis
using assms by simp
next
case (comb name args)
show ?thesis
proof (cases "args = []")
case True
thus ?thesis
using assms comb by fastforce
next
case False
show ?thesis
unfolding ‹t = _›
proof (rule assms)
fix arg
assume "arg ∈ set args"
then have "(arg, t) ∈ measure size"
unfolding ‹t = _›
by (induction args) auto
moreover have "linear arg"
using ‹arg ∈ set args› ‹linears args›
by (auto dest: linears_linear)
ultimately show "P arg"
using less by auto
qed fact
qed
qed
qed
context begin
private lemma match_subst_correctness0:
assumes "linear t"
shows "case match t u of
None ⇒ (∀env. subst (convert_term t) env ≠ u) |
Some env ⇒ subst (convert_term t) env = u"
using assms proof (induction t arbitrary: u)
case Free
show ?case
unfolding match.simps
by (fold free_term_def) auto
next
case Const
show ?case
unfolding match.simps
by (fold const_term_def) (auto split: option.splits)
next
case (App t⇩1 t⇩2)
hence linear: "linear t⇩1" "linear t⇩2" "fdisjnt (frees t⇩1) (frees t⇩2)"
by simp+
show ?case
proof (cases "unapp u")
case None
then show ?thesis
apply simp
apply (fold app_term_def)
apply simp
using app_simps(3) is_app_def by blast
next
case (Some u')
then obtain u⇩1 u⇩2 where u: "unapp u = Some (u⇩1, u⇩2)" by (cases u') auto
hence "u = app u⇩1 u⇩2" by auto
note 1 = App(1)[OF ‹linear t⇩1›, of u⇩1]
note 2 = App(2)[OF ‹linear t⇩2›, of u⇩2]
show ?thesis
proof (cases "match t⇩1 u⇩1")
case None
then show ?thesis
using u
apply simp
apply (fold app_term_def)
using 1 by auto
next
case (Some env⇩1)
with 1 have s1: "subst (convert_term t⇩1) env⇩1 = u⇩1" by simp
show ?thesis
proof (cases "match t⇩2 u⇩2")
case None
then show ?thesis
using u
apply simp
apply (fold app_term_def)
using 2 by auto
next
case (Some env⇩2)
with 2 have s2: "subst (convert_term t⇩2) env⇩2 = u⇩2" by simp
note match = ‹match t⇩1 u⇩1 = Some env⇩1› ‹match t⇩2 u⇩2 = Some env⇩2›
let ?env = "env⇩1 ++⇩f env⇩2"
from match have "frees t⇩1 = fmdom env⇩1" "frees t⇩2 = fmdom env⇩2"
by (auto simp: match_dom)
with linear have "env⇩1 = fmrestrict_fset (frees t⇩1) ?env" "env⇩2 = fmrestrict_fset (frees t⇩2) ?env"
apply auto
apply (auto simp: fmfilter_alt_defs)
apply (subst fmfilter_false; auto simp: fdisjnt_alt_def intro: fmdomI)+
done
with s1 s2 have "subst (convert_term t⇩1) ?env = u⇩1" "subst (convert_term t⇩2) ?env = u⇩2"
using linear
by (metis subst_restrict' convert_term_frees linear_implies_no_abs)+
then show ?thesis
using match unfolding ‹u = _›
apply simp
apply (fold app_term_def)
by simp
qed
qed
qed
qed auto
lemma match_subst_some[simp]:
"match t u = Some env ⟹ linear t ⟹ subst (convert_term t) env = u"
by (metis (mono_tags) match_subst_correctness0 option.simps(5))
lemma match_subst_none:
"match t u = None ⟹ linear t ⟹ subst (convert_term t) env = u ⟹ False"
by (metis (mono_tags, lifting) match_subst_correctness0 option.simps(4))
end
lemma match_matches: "match t u = Some env ⟹ linear t ⟹ t ≲ u"
by (metis match_subst_some linear_implies_no_abs convert_term_id matchesI)
lemma overlapping_var1I: "overlapping (Free name) t"
proof (intro overlappingI matchesI)
show "subst (Free name) (fmap_of_list [(name, t)]) = t"
by simp
next
show "subst t fmempty = t"
by simp
qed
lemma overlapping_var2I: "overlapping t (Free name)"
proof (intro overlappingI matchesI)
show "subst (Free name) (fmap_of_list [(name, t)]) = t"
by simp
next
show "subst t fmempty = t"
by simp
qed
lemma non_overlapping_appI1: "non_overlapping t⇩1 u⇩1 ⟹ non_overlapping (t⇩1 $ t⇩2) (u⇩1 $ u⇩2)"
unfolding overlapping_def matches_def by auto
lemma non_overlapping_appI2: "non_overlapping t⇩2 u⇩2 ⟹ non_overlapping (t⇩1 $ t⇩2) (u⇩1 $ u⇩2)"
unfolding overlapping_def matches_def by auto
lemma non_overlapping_app_constI: "non_overlapping (t⇩1 $ t⇩2) (Const name)"
unfolding overlapping_def matches_def by simp
lemma non_overlapping_const_appI: "non_overlapping (Const name) (t⇩1 $ t⇩2)"
unfolding overlapping_def matches_def by simp
lemma non_overlapping_const_constI: "x ≠ y ⟹ non_overlapping (Const x) (Const y)"
unfolding overlapping_def matches_def by simp
lemma match_overlapping:
assumes "linear t⇩1" "linear t⇩2"
assumes "match t⇩1 u = Some env⇩1" "match t⇩2 u = Some env⇩2"
shows "overlapping t⇩1 t⇩2"
proof -
define env⇩1' where "env⇩1' = (fmmap convert_term env⇩1 :: (name, term) fmap)"
define env⇩2' where "env⇩2' = (fmmap convert_term env⇩2 :: (name, term) fmap)"
from assms have "match t⇩1 (convert_term u :: term) = Some env⇩1'" "match t⇩2 (convert_term u :: term) = Some env⇩2'"
unfolding env⇩1'_def env⇩2'_def
by (metis convert_term_match)+
with assms show ?thesis
by (metis overlappingI match_matches)
qed
end