17 type searchinfo = |
17 type searchinfo = |
18 theory |
18 theory |
19 * int (* maxidx *) |
19 * int (* maxidx *) |
20 * Zipper.T (* focusterm to search under *) |
20 * Zipper.T (* focusterm to search under *) |
21 |
21 |
22 exception eqsubst_occL_exp of |
22 datatype 'a skipseq = SkipMore of int | SkipSeq of 'a Seq.seq Seq.seq |
23 string * int list * thm list * int * thm |
23 |
24 |
24 val skip_first_asm_occs_search : |
25 (* low level substitution functions *) |
25 ('a -> 'b -> 'c Seq.seq Seq.seq) -> |
26 val apply_subst_in_asm : |
26 'a -> int -> 'b -> 'c skipseq |
27 int -> |
27 val skip_first_occs_search : |
28 thm -> |
28 int -> ('a -> 'b -> 'c Seq.seq Seq.seq) -> 'a -> 'b -> 'c Seq.seq |
29 thm -> |
29 val skipto_skipseq : int -> 'a Seq.seq Seq.seq -> 'a skipseq |
30 (cterm list * int * 'a * thm) * match -> thm Seq.seq |
30 |
31 val apply_subst_in_concl : |
31 (* tactics *) |
32 int -> |
32 val eqsubst_asm_tac : |
33 thm -> |
33 Proof.context -> |
34 cterm list * thm -> |
34 int list -> thm list -> int -> tactic |
35 thm -> match -> thm Seq.seq |
35 val eqsubst_asm_tac' : |
36 |
36 Proof.context -> |
37 (* matching/unification within zippers *) |
37 (searchinfo -> int -> term -> match skipseq) -> |
38 val clean_match_z : |
38 int -> thm -> int -> tactic |
39 theory -> term -> Zipper.T -> match option |
39 val eqsubst_tac : |
40 val clean_unify_z : |
40 Proof.context -> |
41 theory -> int -> term -> Zipper.T -> match Seq.seq |
41 int list -> (* list of occurences to rewrite, use [0] for any *) |
42 |
42 thm list -> int -> tactic |
43 (* skipping things in seq seq's *) |
43 val eqsubst_tac' : |
44 |
44 Proof.context -> (* proof context *) |
45 (* skipping non-empty sub-sequences but when we reach the end |
45 (searchinfo -> term -> match Seq.seq) (* search function *) |
46 of the seq, remembering how much we have left to skip. *) |
46 -> thm (* equation theorem to rewrite with *) |
47 datatype 'a skipseq = SkipMore of int |
47 -> int (* subgoal number in goal theorem *) |
48 | SkipSeq of 'a Seq.seq Seq.seq; |
48 -> thm (* goal theorem *) |
49 |
49 -> thm Seq.seq (* rewritten goal theorem *) |
50 val skip_first_asm_occs_search : |
50 |
51 ('a -> 'b -> 'c Seq.seq Seq.seq) -> |
51 (* search for substitutions *) |
52 'a -> int -> 'b -> 'c skipseq |
52 val valid_match_start : Zipper.T -> bool |
53 val skip_first_occs_search : |
53 val search_lr_all : Zipper.T -> Zipper.T Seq.seq |
54 int -> ('a -> 'b -> 'c Seq.seq Seq.seq) -> 'a -> 'b -> 'c Seq.seq |
54 val search_lr_valid : (Zipper.T -> bool) -> Zipper.T -> Zipper.T Seq.seq |
55 val skipto_skipseq : int -> 'a Seq.seq Seq.seq -> 'a skipseq |
55 val searchf_lr_unify_all : |
56 |
56 searchinfo -> term -> match Seq.seq Seq.seq |
57 (* tactics *) |
57 val searchf_lr_unify_valid : |
58 val eqsubst_asm_tac : |
58 searchinfo -> term -> match Seq.seq Seq.seq |
59 Proof.context -> |
59 val searchf_bt_unify_valid : |
60 int list -> thm list -> int -> tactic |
60 searchinfo -> term -> match Seq.seq Seq.seq |
61 val eqsubst_asm_tac' : |
61 |
62 Proof.context -> |
62 val setup : theory -> theory |
63 (searchinfo -> int -> term -> match skipseq) -> |
|
64 int -> thm -> int -> tactic |
|
65 val eqsubst_tac : |
|
66 Proof.context -> |
|
67 int list -> (* list of occurences to rewrite, use [0] for any *) |
|
68 thm list -> int -> tactic |
|
69 val eqsubst_tac' : |
|
70 Proof.context -> (* proof context *) |
|
71 (searchinfo -> term -> match Seq.seq) (* search function *) |
|
72 -> thm (* equation theorem to rewrite with *) |
|
73 -> int (* subgoal number in goal theorem *) |
|
74 -> thm (* goal theorem *) |
|
75 -> thm Seq.seq (* rewritten goal theorem *) |
|
76 |
|
77 |
|
78 val fakefree_badbounds : |
|
79 (string * typ) list -> |
|
80 term -> |
|
81 (string * typ) list * (string * typ) list * term |
|
82 |
|
83 val mk_foo_match : |
|
84 (term -> term) -> |
|
85 ('a * typ) list -> term -> term |
|
86 |
|
87 (* preparing substitution *) |
|
88 val prep_meta_eq : Proof.context -> thm -> thm list |
|
89 val prep_concl_subst : |
|
90 int -> thm -> (cterm list * thm) * searchinfo |
|
91 val prep_subst_in_asm : |
|
92 int -> thm -> int -> |
|
93 (cterm list * int * int * thm) * searchinfo |
|
94 val prep_subst_in_asms : |
|
95 int -> thm -> |
|
96 ((cterm list * int * int * thm) * searchinfo) list |
|
97 val prep_zipper_match : |
|
98 Zipper.T -> term * ((string * typ) list * (string * typ) list * term) |
|
99 |
|
100 (* search for substitutions *) |
|
101 val valid_match_start : Zipper.T -> bool |
|
102 val search_lr_all : Zipper.T -> Zipper.T Seq.seq |
|
103 val search_lr_valid : (Zipper.T -> bool) -> Zipper.T -> Zipper.T Seq.seq |
|
104 val searchf_lr_unify_all : |
|
105 searchinfo -> term -> match Seq.seq Seq.seq |
|
106 val searchf_lr_unify_valid : |
|
107 searchinfo -> term -> match Seq.seq Seq.seq |
|
108 val searchf_bt_unify_valid : |
|
109 searchinfo -> term -> match Seq.seq Seq.seq |
|
110 |
|
111 (* Isar level hooks *) |
|
112 val eqsubst_asm_meth : Proof.context -> int list -> thm list -> Proof.method |
|
113 val eqsubst_meth : Proof.context -> int list -> thm list -> Proof.method |
|
114 val setup : theory -> theory |
|
115 |
63 |
116 end; |
64 end; |
117 |
65 |
118 structure EqSubst: EQSUBST = |
66 structure EqSubst: EQSUBST = |
119 struct |
67 struct |
140 (* skipping non-empty sub-sequences but when we reach the end |
88 (* skipping non-empty sub-sequences but when we reach the end |
141 of the seq, remembering how much we have left to skip. *) |
89 of the seq, remembering how much we have left to skip. *) |
142 datatype 'a skipseq = SkipMore of int |
90 datatype 'a skipseq = SkipMore of int |
143 | SkipSeq of 'a Seq.seq Seq.seq; |
91 | SkipSeq of 'a Seq.seq Seq.seq; |
144 (* given a seqseq, skip the first m non-empty seq's, note deficit *) |
92 (* given a seqseq, skip the first m non-empty seq's, note deficit *) |
145 fun skipto_skipseq m s = |
93 fun skipto_skipseq m s = |
146 let |
94 let |
147 fun skip_occs n sq = |
95 fun skip_occs n sq = |
148 case Seq.pull sq of |
96 case Seq.pull sq of |
149 NONE => SkipMore n |
97 NONE => SkipMore n |
150 | SOME (h,t) => |
98 | SOME (h,t) => |
151 (case Seq.pull h of NONE => skip_occs n t |
99 (case Seq.pull h of NONE => skip_occs n t |
152 | SOME _ => if n <= 1 then SkipSeq (Seq.cons h t) |
100 | SOME _ => if n <= 1 then SkipSeq (Seq.cons h t) |
153 else skip_occs (n - 1) t) |
101 else skip_occs (n - 1) t) |
154 in (skip_occs m s) end; |
102 in (skip_occs m s) end; |
155 |
103 |
156 (* note: outerterm is the taget with the match replaced by a bound |
104 (* note: outerterm is the taget with the match replaced by a bound |
157 variable : ie: "P lhs" beocmes "%x. P x" |
105 variable : ie: "P lhs" beocmes "%x. P x" |
158 insts is the types of instantiations of vars in lhs |
106 insts is the types of instantiations of vars in lhs |
159 and typinsts is the type instantiations of types in the lhs |
107 and typinsts is the type instantiations of types in the lhs |
160 Note: Final rule is the rule lifted into the ontext of the |
108 Note: Final rule is the rule lifted into the ontext of the |
161 taget thm. *) |
109 taget thm. *) |
162 fun mk_foo_match mkuptermfunc Ts t = |
110 fun mk_foo_match mkuptermfunc Ts t = |
163 let |
111 let |
164 val ty = Term.type_of t |
112 val ty = Term.type_of t |
165 val bigtype = (rev (map snd Ts)) ---> ty |
113 val bigtype = (rev (map snd Ts)) ---> ty |
166 fun mk_foo 0 t = t |
114 fun mk_foo 0 t = t |
167 | mk_foo i t = mk_foo (i - 1) (t $ (Bound (i - 1))) |
115 | mk_foo i t = mk_foo (i - 1) (t $ (Bound (i - 1))) |
168 val num_of_bnds = (length Ts) |
116 val num_of_bnds = (length Ts) |
170 val foo_term = mk_foo num_of_bnds (Bound num_of_bnds) |
118 val foo_term = mk_foo num_of_bnds (Bound num_of_bnds) |
171 in Abs("fooabs", bigtype, mkuptermfunc foo_term) end; |
119 in Abs("fooabs", bigtype, mkuptermfunc foo_term) end; |
172 |
120 |
173 (* T is outer bound vars, n is number of locally bound vars *) |
121 (* T is outer bound vars, n is number of locally bound vars *) |
174 (* THINK: is order of Ts correct...? or reversed? *) |
122 (* THINK: is order of Ts correct...? or reversed? *) |
175 fun fakefree_badbounds Ts t = |
123 fun mk_fake_bound_name n = ":b_" ^ n; |
176 let val (FakeTs,Ts,newnames) = |
124 fun fakefree_badbounds Ts t = |
177 List.foldr (fn ((n,ty),(FakeTs,Ts,usednames)) => |
125 let val (FakeTs,Ts,newnames) = |
|
126 List.foldr (fn ((n,ty),(FakeTs,Ts,usednames)) => |
178 let val newname = singleton (Name.variant_list usednames) n |
127 let val newname = singleton (Name.variant_list usednames) n |
179 in ((RWTools.mk_fake_bound_name newname,ty)::FakeTs, |
128 in ((mk_fake_bound_name newname,ty)::FakeTs, |
180 (newname,ty)::Ts, |
129 (newname,ty)::Ts, |
181 newname::usednames) end) |
130 newname::usednames) end) |
182 ([],[],[]) |
131 ([],[],[]) |
183 Ts |
132 Ts |
184 in (FakeTs, Ts, Term.subst_bounds (map Free FakeTs, t)) end; |
133 in (FakeTs, Ts, Term.subst_bounds (map Free FakeTs, t)) end; |
185 |
134 |
186 (* before matching we need to fake the bound vars that are missing an |
135 (* before matching we need to fake the bound vars that are missing an |
187 abstraction. In this function we additionally construct the |
136 abstraction. In this function we additionally construct the |
188 abstraction environment, and an outer context term (with the focus |
137 abstraction environment, and an outer context term (with the focus |
189 abstracted out) for use in rewriting with RWInst.rw *) |
138 abstracted out) for use in rewriting with RWInst.rw *) |
190 fun prep_zipper_match z = |
139 fun prep_zipper_match z = |
191 let |
140 let |
192 val t = Zipper.trm z |
141 val t = Zipper.trm z |
193 val c = Zipper.ctxt z |
142 val c = Zipper.ctxt z |
194 val Ts = Zipper.C.nty_ctxt c |
143 val Ts = Zipper.C.nty_ctxt c |
195 val (FakeTs', Ts', t') = fakefree_badbounds Ts t |
144 val (FakeTs', Ts', t') = fakefree_badbounds Ts t |
196 val absterm = mk_foo_match (Zipper.C.apply c) Ts' t' |
145 val absterm = mk_foo_match (Zipper.C.apply c) Ts' t' |
197 in |
146 in |
198 (t', (FakeTs', Ts', absterm)) |
147 (t', (FakeTs', Ts', absterm)) |
199 end; |
148 end; |
200 |
149 |
201 (* Matching and Unification with exception handled *) |
150 (* Unification with exception handled *) |
202 fun clean_match thy (a as (pat, t)) = |
|
203 let val (tyenv, tenv) = Pattern.match thy a (Vartab.empty, Vartab.empty) |
|
204 in SOME (Vartab.dest tyenv, Vartab.dest tenv) |
|
205 end handle Pattern.MATCH => NONE; |
|
206 |
|
207 (* given theory, max var index, pat, tgt; returns Seq of instantiations *) |
151 (* given theory, max var index, pat, tgt; returns Seq of instantiations *) |
208 fun clean_unify thry ix (a as (pat, tgt)) = |
152 fun clean_unify thry ix (a as (pat, tgt)) = |
209 let |
153 let |
210 (* type info will be re-derived, maybe this can be cached |
154 (* type info will be re-derived, maybe this can be cached |
211 for efficiency? *) |
155 for efficiency? *) |
240 (Seq.make (clean_unify' useq)) |
184 (Seq.make (clean_unify' useq)) |
241 end |
185 end |
242 | NONE => Seq.empty |
186 | NONE => Seq.empty |
243 end; |
187 end; |
244 |
188 |
245 (* Matching and Unification for zippers *) |
189 (* Unification for zippers *) |
246 (* Note: Ts is a modified version of the original names of the outer |
190 (* Note: Ts is a modified version of the original names of the outer |
247 bound variables. New names have been introduced to make sure they are |
191 bound variables. New names have been introduced to make sure they are |
248 unique w.r.t all names in the term and each other. usednames' is |
192 unique w.r.t all names in the term and each other. usednames' is |
249 oldnames + new names. *) |
193 oldnames + new names. *) |
250 fun clean_match_z thy pat z = |
|
251 let val (t, (FakeTs,Ts,absterm)) = prep_zipper_match z in |
|
252 case clean_match thy (pat, t) of |
|
253 NONE => NONE |
|
254 | SOME insts => SOME (insts, FakeTs, Ts, absterm) end; |
|
255 (* ix = max var index *) |
194 (* ix = max var index *) |
256 fun clean_unify_z sgn ix pat z = |
195 fun clean_unify_z sgn ix pat z = |
257 let val (t, (FakeTs, Ts,absterm)) = prep_zipper_match z in |
196 let val (t, (FakeTs, Ts,absterm)) = prep_zipper_match z in |
258 Seq.map (fn insts => (insts, FakeTs, Ts, absterm)) |
197 Seq.map (fn insts => (insts, FakeTs, Ts, absterm)) |
259 (clean_unify sgn ix (t, pat)) end; |
198 (clean_unify sgn ix (t, pat)) end; |
260 |
|
261 |
|
262 (* FOR DEBUGGING... |
|
263 type trace_subst_errT = int (* subgoal *) |
|
264 * thm (* thm with all goals *) |
|
265 * (cterm list (* certified free var placeholders for vars *) |
|
266 * thm) (* trivial thm of goal concl *) |
|
267 (* possible matches/unifiers *) |
|
268 * thm (* rule *) |
|
269 * (((indexname * typ) list (* type instantiations *) |
|
270 * (indexname * term) list ) (* term instantiations *) |
|
271 * (string * typ) list (* Type abs env *) |
|
272 * term) (* outer term *); |
|
273 |
|
274 val trace_subst_err = (Unsynchronized.ref NONE : trace_subst_errT option Unsynchronized.ref); |
|
275 val trace_subst_search = Unsynchronized.ref false; |
|
276 exception trace_subst_exp of trace_subst_errT; |
|
277 *) |
|
278 |
199 |
279 |
200 |
280 fun bot_left_leaf_of (l $ r) = bot_left_leaf_of l |
201 fun bot_left_leaf_of (l $ r) = bot_left_leaf_of l |
281 | bot_left_leaf_of (Abs(s,ty,t)) = bot_left_leaf_of t |
202 | bot_left_leaf_of (Abs(s,ty,t)) = bot_left_leaf_of t |
282 | bot_left_leaf_of x = x; |
203 | bot_left_leaf_of x = x; |
283 |
204 |
284 (* Avoid considering replacing terms which have a var at the head as |
205 (* Avoid considering replacing terms which have a var at the head as |
285 they always succeed trivially, and uninterestingly. *) |
206 they always succeed trivially, and uninterestingly. *) |
286 fun valid_match_start z = |
207 fun valid_match_start z = |
287 (case bot_left_leaf_of (Zipper.trm z) of |
208 (case bot_left_leaf_of (Zipper.trm z) of |
288 Var _ => false |
209 Var _ => false |
289 | _ => true); |
210 | _ => true); |
290 |
211 |
291 (* search from top, left to right, then down *) |
212 (* search from top, left to right, then down *) |
292 val search_lr_all = ZipperSearch.all_bl_ur; |
213 val search_lr_all = ZipperSearch.all_bl_ur; |
293 |
214 |
294 (* search from top, left to right, then down *) |
215 (* search from top, left to right, then down *) |
295 fun search_lr_valid validf = |
216 fun search_lr_valid validf = |
296 let |
217 let |
297 fun sf_valid_td_lr z = |
218 fun sf_valid_td_lr z = |
298 let val here = if validf z then [Zipper.Here z] else [] in |
219 let val here = if validf z then [Zipper.Here z] else [] in |
299 case Zipper.trm z |
220 case Zipper.trm z |
300 of _ $ _ => [Zipper.LookIn (Zipper.move_down_left z)] |
221 of _ $ _ => [Zipper.LookIn (Zipper.move_down_left z)] |
301 @ here |
222 @ here |
302 @ [Zipper.LookIn (Zipper.move_down_right z)] |
223 @ [Zipper.LookIn (Zipper.move_down_right z)] |
303 | Abs _ => here @ [Zipper.LookIn (Zipper.move_down_abs z)] |
224 | Abs _ => here @ [Zipper.LookIn (Zipper.move_down_abs z)] |
304 | _ => here |
225 | _ => here |
305 end; |
226 end; |
306 in Zipper.lzy_search sf_valid_td_lr end; |
227 in Zipper.lzy_search sf_valid_td_lr end; |
307 |
228 |
308 (* search from bottom to top, left to right *) |
229 (* search from bottom to top, left to right *) |
309 |
230 |
310 fun search_bt_valid validf = |
231 fun search_bt_valid validf = |
311 let |
232 let |
312 fun sf_valid_td_lr z = |
233 fun sf_valid_td_lr z = |
313 let val here = if validf z then [Zipper.Here z] else [] in |
234 let val here = if validf z then [Zipper.Here z] else [] in |
314 case Zipper.trm z |
235 case Zipper.trm z |
315 of _ $ _ => [Zipper.LookIn (Zipper.move_down_left z), |
236 of _ $ _ => [Zipper.LookIn (Zipper.move_down_left z), |
316 Zipper.LookIn (Zipper.move_down_right z)] @ here |
237 Zipper.LookIn (Zipper.move_down_right z)] @ here |
317 | Abs _ => [Zipper.LookIn (Zipper.move_down_abs z)] @ here |
238 | Abs _ => [Zipper.LookIn (Zipper.move_down_abs z)] @ here |
318 | _ => here |
239 | _ => here |
319 end; |
240 end; |
320 in Zipper.lzy_search sf_valid_td_lr end; |
241 in Zipper.lzy_search sf_valid_td_lr end; |
321 |
242 |
322 fun searchf_unify_gen f (sgn, maxidx, z) lhs = |
243 fun searchf_unify_gen f (sgn, maxidx, z) lhs = |
323 Seq.map (clean_unify_z sgn maxidx lhs) |
244 Seq.map (clean_unify_z sgn maxidx lhs) |
324 (Zipper.limit_apply f z); |
245 (Zipper.limit_apply f z); |
325 |
246 |
326 (* search all unifications *) |
247 (* search all unifications *) |
327 val searchf_lr_unify_all = |
248 val searchf_lr_unify_all = |
328 searchf_unify_gen search_lr_all; |
249 searchf_unify_gen search_lr_all; |
329 |
250 |
330 (* search only for 'valid' unifiers (non abs subterms and non vars) *) |
251 (* search only for 'valid' unifiers (non abs subterms and non vars) *) |
331 val searchf_lr_unify_valid = |
252 val searchf_lr_unify_valid = |
332 searchf_unify_gen (search_lr_valid valid_match_start); |
253 searchf_unify_gen (search_lr_valid valid_match_start); |
333 |
254 |
334 val searchf_bt_unify_valid = |
255 val searchf_bt_unify_valid = |
335 searchf_unify_gen (search_bt_valid valid_match_start); |
256 searchf_unify_gen (search_bt_valid valid_match_start); |
336 |
257 |
406 let val nprems = Thm.nprems_of th in |
325 let val nprems = Thm.nprems_of th in |
407 if nprems < i then Seq.empty else |
326 if nprems < i then Seq.empty else |
408 let val thmseq = (Seq.of_list thms) |
327 let val thmseq = (Seq.of_list thms) |
409 fun apply_occ occ th = |
328 fun apply_occ occ th = |
410 thmseq |> Seq.maps |
329 thmseq |> Seq.maps |
411 (fn r => eqsubst_tac' |
330 (fn r => eqsubst_tac' |
412 ctxt |
331 ctxt |
413 (skip_first_occs_search |
332 (skip_first_occs_search |
414 occ searchf_lr_unify_valid) r |
333 occ searchf_lr_unify_valid) r |
415 (i + ((Thm.nprems_of th) - nprems)) |
334 (i + ((Thm.nprems_of th) - nprems)) |
416 th); |
335 th); |
417 val sortedoccL = |
336 val sortedoccL = |
418 Library.sort (Library.rev_order o Library.int_ord) occL; |
337 Library.sort (Library.rev_order o Library.int_ord) occL; |
419 in |
338 in |
420 Seq.map distinct_subgoals (Seq.EVERY (map apply_occ sortedoccL) th) |
339 Seq.map distinct_subgoals (Seq.EVERY (map apply_occ sortedoccL) th) |
421 end |
340 end |
422 end |
341 end; |
423 handle THM _ => raise eqsubst_occL_exp ("THM",occL,thms,i,th); |
|
424 |
342 |
425 |
343 |
426 (* inthms are the given arguments in Isar, and treated as eqstep with |
344 (* inthms are the given arguments in Isar, and treated as eqstep with |
427 the first one, then the second etc *) |
345 the first one, then the second etc *) |
428 fun eqsubst_meth ctxt occL inthms = |
346 fun eqsubst_meth ctxt occL inthms = |