25722
|
1 |
(* $Id$ *)
|
|
2 |
|
25727
|
3 |
theory VC_Condition
|
25722
|
4 |
imports "../Nominal"
|
|
5 |
begin
|
|
6 |
|
|
7 |
text {*
|
|
8 |
We give here two examples that show if we use the variable
|
|
9 |
convention carelessly in rule inductions, we might end
|
|
10 |
up with faulty lemmas. The point is that the examples
|
|
11 |
are not variable-convention compatible and therefore in the
|
|
12 |
nominal package one is protected from such bogus reasoning.
|
|
13 |
*}
|
|
14 |
|
|
15 |
text {*
|
|
16 |
We define alpha-equated lambda-terms as usual. *}
|
|
17 |
atom_decl name
|
|
18 |
|
|
19 |
nominal_datatype lam =
|
|
20 |
Var "name"
|
|
21 |
| App "lam" "lam"
|
|
22 |
| Lam "\<guillemotleft>name\<guillemotright>lam" ("Lam [_]._" [100,100] 100)
|
|
23 |
|
|
24 |
text {*
|
|
25 |
The inductive relation 'unbind' unbinds the top-most
|
|
26 |
binders of a lambda-term; this relation is obviously
|
|
27 |
not a function, since it does not respect alpha-
|
|
28 |
equivalence. However as a relation 'unbind' is ok and
|
|
29 |
a similar relation has been used in our formalisation
|
|
30 |
of the algorithm W. *}
|
|
31 |
inductive
|
|
32 |
unbind :: "lam \<Rightarrow> name list \<Rightarrow> lam \<Rightarrow> bool" ("_ \<mapsto> _,_" [60,60,60] 60)
|
|
33 |
where
|
|
34 |
u_var: "(Var a) \<mapsto> [],(Var a)"
|
|
35 |
| u_app: "(App t1 t2) \<mapsto> [],(App t1 t2)"
|
|
36 |
| u_lam: "t\<mapsto>xs,t' \<Longrightarrow> (Lam [x].t) \<mapsto> (x#xs),t'"
|
|
37 |
|
|
38 |
text {*
|
|
39 |
We can show that Lam [x].Lam [x].Var x unbinds to [x,x],Var x
|
|
40 |
and also to [z,y],Var y (though the proof for the second is a
|
|
41 |
bit clumsy). *}
|
|
42 |
lemma unbind_lambda_lambda1:
|
|
43 |
shows "Lam [x].Lam [x].(Var x)\<mapsto>[x,x],(Var x)"
|
|
44 |
by (auto intro: unbind.intros)
|
|
45 |
|
|
46 |
lemma unbind_lambda_lambda2:
|
|
47 |
shows "Lam [x].Lam [x].(Var x)\<mapsto>[y,z],(Var z)"
|
|
48 |
proof -
|
|
49 |
have "Lam [x].Lam [x].(Var x) = Lam [y].Lam [z].(Var z)"
|
|
50 |
by (auto simp add: lam.inject alpha calc_atm abs_fresh fresh_atm)
|
|
51 |
moreover
|
|
52 |
have "Lam [y].Lam [z].(Var z) \<mapsto> [y,z],(Var z)"
|
|
53 |
by (auto intro: unbind.intros)
|
|
54 |
ultimately
|
|
55 |
show "Lam [x].Lam [x].(Var x)\<mapsto>[y,z],(Var z)" by simp
|
|
56 |
qed
|
|
57 |
|
|
58 |
text {* Unbind is equivariant ...*}
|
|
59 |
equivariance unbind
|
|
60 |
|
|
61 |
text {*
|
|
62 |
... but it is not variable-convention compatible (see Urban,
|
|
63 |
Berghofer, Norrish [2007] for more details). This condition
|
|
64 |
requires for rule u_lam to have the binder x being not a free variable
|
|
65 |
in the rule's conclusion. Because this condition is not satisfied,
|
|
66 |
Isabelle will not derive a strong induction principle for 'unbind'
|
|
67 |
- that means Isabelle does not allow us to use the variable
|
|
68 |
convention in induction proofs over 'unbind'. We can, however,
|
|
69 |
force Isabelle to derive the strengthening induction principle
|
|
70 |
and see what happens. *}
|
|
71 |
|
|
72 |
nominal_inductive unbind
|
|
73 |
sorry
|
|
74 |
|
|
75 |
text {*
|
|
76 |
To obtain a faulty lemma, we introduce the function 'bind'
|
|
77 |
which takes a list of names and abstracts away these names in
|
|
78 |
a given lambda-term. *}
|
|
79 |
fun
|
|
80 |
bind :: "name list \<Rightarrow> lam \<Rightarrow> lam"
|
|
81 |
where
|
|
82 |
"bind [] t = t"
|
|
83 |
| "bind (x#xs) t = Lam [x].(bind xs t)"
|
|
84 |
|
|
85 |
text {*
|
|
86 |
Although not necessary for our main argument below, we can
|
|
87 |
easily prove that bind undoes the unbinding. *}
|
|
88 |
lemma bind_unbind:
|
|
89 |
assumes a: "t \<mapsto> xs,t'"
|
|
90 |
shows "t = bind xs t'"
|
|
91 |
using a by (induct) (auto)
|
|
92 |
|
|
93 |
text {*
|
|
94 |
The next lemma shows by induction on xs that if x is a free
|
|
95 |
variable in t and x does not occur in xs, then x is a free
|
|
96 |
variable in bind xs t. In the nominal tradition we formulate
|
|
97 |
'is a free variable in' as 'is not fresh for'. *}
|
|
98 |
lemma free_variable:
|
|
99 |
fixes x::"name"
|
|
100 |
assumes a: "\<not>(x\<sharp>t)" and b: "x\<sharp>xs"
|
|
101 |
shows "\<not>(x\<sharp>bind xs t)"
|
|
102 |
using a b
|
|
103 |
by (induct xs)
|
|
104 |
(auto simp add: fresh_list_cons abs_fresh fresh_atm)
|
|
105 |
|
|
106 |
text {*
|
|
107 |
Now comes the faulty lemma. It is derived using the
|
|
108 |
variable convention (i.e. our strong induction principle).
|
|
109 |
This faulty lemma states that if t unbinds to x::xs and t',
|
|
110 |
and x is a free variable in t', then it is also a free
|
|
111 |
variable in bind xs t'. We show this lemma by assuming that
|
|
112 |
the binder x is fresh w.r.t. to the xs unbound previously. *}
|
|
113 |
|
|
114 |
lemma faulty1:
|
|
115 |
assumes a: "t\<mapsto>(x#xs),t'"
|
|
116 |
shows "\<not>(x\<sharp>t') \<Longrightarrow> \<not>(x\<sharp>bind xs t')"
|
|
117 |
using a
|
|
118 |
by (nominal_induct t xs'\<equiv>"x#xs" t' avoiding: xs rule: unbind.strong_induct)
|
|
119 |
(simp_all add: free_variable)
|
|
120 |
|
|
121 |
text {*
|
|
122 |
Obviously the faulty lemma does not hold, for example, in
|
|
123 |
case Lam [x].Lam [x].(Var x) \<mapsto> [x,x],(Var x). Therefore,
|
|
124 |
we can prove False. *}
|
|
125 |
|
|
126 |
lemma false1:
|
|
127 |
shows "False"
|
|
128 |
proof -
|
|
129 |
have "Lam [x].Lam [x].(Var x)\<mapsto>[x,x],(Var x)"
|
|
130 |
and "\<not>(x\<sharp>Var x)" by (simp_all add: unbind_lambda_lambda1 fresh_atm)
|
|
131 |
then have "\<not>(x\<sharp>(bind [x] (Var x)))" by (rule faulty1)
|
|
132 |
moreover
|
|
133 |
have "x\<sharp>(bind [x] (Var x))" by (simp add: abs_fresh)
|
|
134 |
ultimately
|
|
135 |
show "False" by simp
|
|
136 |
qed
|
|
137 |
|
|
138 |
text {*
|
|
139 |
The next example is slightly simpler, but looks more
|
|
140 |
contrived than 'unbind'. This example, caled 'strip' just
|
|
141 |
strips off the top-most binders from lambdas. *}
|
|
142 |
|
|
143 |
inductive
|
|
144 |
strip :: "lam \<Rightarrow> lam \<Rightarrow> bool" ("_ \<rightarrow> _" [60,60] 60)
|
|
145 |
where
|
|
146 |
s_var: "(Var a) \<rightarrow> (Var a)"
|
|
147 |
| s_app: "(App t1 t2) \<rightarrow> (App t1 t2)"
|
|
148 |
| s_lam: "t \<rightarrow> t' \<Longrightarrow> (Lam [x].t) \<rightarrow> t'"
|
|
149 |
|
|
150 |
text {*
|
|
151 |
The relation is equivariant but we have to use again
|
|
152 |
sorry to derive a strong induction principle. *}
|
|
153 |
|
|
154 |
equivariance strip
|
|
155 |
|
|
156 |
nominal_inductive strip
|
|
157 |
sorry
|
|
158 |
|
|
159 |
text {*
|
|
160 |
The faulty lemma shows that a variable that is fresh
|
|
161 |
for a term is also fresh for the term after striping. *}
|
|
162 |
|
|
163 |
lemma faulty2:
|
|
164 |
fixes x::"name"
|
|
165 |
assumes a: "t \<rightarrow> t'"
|
|
166 |
shows "x\<sharp>t \<Longrightarrow> x\<sharp>t'"
|
|
167 |
using a
|
|
168 |
by (nominal_induct t t'\<equiv>t' avoiding: t' rule: strip.strong_induct)
|
|
169 |
(auto simp add: abs_fresh)
|
|
170 |
|
|
171 |
text {*
|
|
172 |
Obviously Lam [x].Var x is a counter example to this lemma. *}
|
|
173 |
|
|
174 |
lemma false2:
|
|
175 |
shows "False"
|
|
176 |
proof -
|
|
177 |
have "Lam [x].(Var x) \<rightarrow> (Var x)" by (auto intro: strip.intros)
|
|
178 |
moreover
|
|
179 |
have "x\<sharp>Lam [x].(Var x)" by (simp add: abs_fresh)
|
|
180 |
ultimately have "x\<sharp>(Var x)" by (simp only: faulty2)
|
|
181 |
then show "False" by (simp add: fresh_atm)
|
|
182 |
qed
|
|
183 |
|
|
184 |
end |