|
1 (* Title: HOL/Tools/old_recdef.ML |
|
2 Author: Konrad Slind, Cambridge University Computer Laboratory |
|
3 Author: Lucas Dixon, University of Edinburgh |
|
4 |
|
5 Old TFL/recdef package. |
|
6 *) |
|
7 |
|
8 signature CASE_SPLIT = |
|
9 sig |
|
10 (* try to recursively split conjectured thm to given list of thms *) |
|
11 val splitto : Proof.context -> thm list -> thm -> thm |
|
12 end; |
|
13 |
|
14 signature UTILS = |
|
15 sig |
|
16 exception ERR of {module: string, func: string, mesg: string} |
|
17 val end_itlist: ('a -> 'a -> 'a) -> 'a list -> 'a |
|
18 val itlist2: ('a -> 'b -> 'c -> 'c) -> 'a list -> 'b list -> 'c -> 'c |
|
19 val pluck: ('a -> bool) -> 'a list -> 'a * 'a list |
|
20 val zip3: 'a list -> 'b list -> 'c list -> ('a*'b*'c) list |
|
21 val take: ('a -> 'b) -> int * 'a list -> 'b list |
|
22 end; |
|
23 |
|
24 signature USYNTAX = |
|
25 sig |
|
26 datatype lambda = VAR of {Name : string, Ty : typ} |
|
27 | CONST of {Name : string, Ty : typ} |
|
28 | COMB of {Rator: term, Rand : term} |
|
29 | LAMB of {Bvar : term, Body : term} |
|
30 |
|
31 val alpha : typ |
|
32 |
|
33 (* Types *) |
|
34 val type_vars : typ -> typ list |
|
35 val type_varsl : typ list -> typ list |
|
36 val mk_vartype : string -> typ |
|
37 val is_vartype : typ -> bool |
|
38 val strip_prod_type : typ -> typ list |
|
39 |
|
40 (* Terms *) |
|
41 val free_vars_lr : term -> term list |
|
42 val type_vars_in_term : term -> typ list |
|
43 val dest_term : term -> lambda |
|
44 |
|
45 (* Prelogic *) |
|
46 val inst : (typ*typ) list -> term -> term |
|
47 |
|
48 (* Construction routines *) |
|
49 val mk_abs :{Bvar : term, Body : term} -> term |
|
50 |
|
51 val mk_imp :{ant : term, conseq : term} -> term |
|
52 val mk_select :{Bvar : term, Body : term} -> term |
|
53 val mk_forall :{Bvar : term, Body : term} -> term |
|
54 val mk_exists :{Bvar : term, Body : term} -> term |
|
55 val mk_conj :{conj1 : term, conj2 : term} -> term |
|
56 val mk_disj :{disj1 : term, disj2 : term} -> term |
|
57 val mk_pabs :{varstruct : term, body : term} -> term |
|
58 |
|
59 (* Destruction routines *) |
|
60 val dest_const: term -> {Name : string, Ty : typ} |
|
61 val dest_comb : term -> {Rator : term, Rand : term} |
|
62 val dest_abs : string list -> term -> {Bvar : term, Body : term} * string list |
|
63 val dest_eq : term -> {lhs : term, rhs : term} |
|
64 val dest_imp : term -> {ant : term, conseq : term} |
|
65 val dest_forall : term -> {Bvar : term, Body : term} |
|
66 val dest_exists : term -> {Bvar : term, Body : term} |
|
67 val dest_neg : term -> term |
|
68 val dest_conj : term -> {conj1 : term, conj2 : term} |
|
69 val dest_disj : term -> {disj1 : term, disj2 : term} |
|
70 val dest_pair : term -> {fst : term, snd : term} |
|
71 val dest_pabs : string list -> term -> {varstruct : term, body : term, used : string list} |
|
72 |
|
73 val lhs : term -> term |
|
74 val rhs : term -> term |
|
75 val rand : term -> term |
|
76 |
|
77 (* Query routines *) |
|
78 val is_imp : term -> bool |
|
79 val is_forall : term -> bool |
|
80 val is_exists : term -> bool |
|
81 val is_neg : term -> bool |
|
82 val is_conj : term -> bool |
|
83 val is_disj : term -> bool |
|
84 val is_pair : term -> bool |
|
85 val is_pabs : term -> bool |
|
86 |
|
87 (* Construction of a term from a list of Preterms *) |
|
88 val list_mk_abs : (term list * term) -> term |
|
89 val list_mk_imp : (term list * term) -> term |
|
90 val list_mk_forall : (term list * term) -> term |
|
91 val list_mk_conj : term list -> term |
|
92 |
|
93 (* Destructing a term to a list of Preterms *) |
|
94 val strip_comb : term -> (term * term list) |
|
95 val strip_abs : term -> (term list * term) |
|
96 val strip_imp : term -> (term list * term) |
|
97 val strip_forall : term -> (term list * term) |
|
98 val strip_exists : term -> (term list * term) |
|
99 val strip_disj : term -> term list |
|
100 |
|
101 (* Miscellaneous *) |
|
102 val mk_vstruct : typ -> term list -> term |
|
103 val gen_all : term -> term |
|
104 val find_term : (term -> bool) -> term -> term option |
|
105 val dest_relation : term -> term * term * term |
|
106 val is_WFR : term -> bool |
|
107 val ARB : typ -> term |
|
108 end; |
|
109 |
|
110 signature DCTERM = |
|
111 sig |
|
112 val dest_comb: cterm -> cterm * cterm |
|
113 val dest_abs: string option -> cterm -> cterm * cterm |
|
114 val capply: cterm -> cterm -> cterm |
|
115 val cabs: cterm -> cterm -> cterm |
|
116 val mk_conj: cterm * cterm -> cterm |
|
117 val mk_disj: cterm * cterm -> cterm |
|
118 val mk_exists: cterm * cterm -> cterm |
|
119 val dest_conj: cterm -> cterm * cterm |
|
120 val dest_const: cterm -> {Name: string, Ty: typ} |
|
121 val dest_disj: cterm -> cterm * cterm |
|
122 val dest_eq: cterm -> cterm * cterm |
|
123 val dest_exists: cterm -> cterm * cterm |
|
124 val dest_forall: cterm -> cterm * cterm |
|
125 val dest_imp: cterm -> cterm * cterm |
|
126 val dest_neg: cterm -> cterm |
|
127 val dest_pair: cterm -> cterm * cterm |
|
128 val dest_var: cterm -> {Name:string, Ty:typ} |
|
129 val is_conj: cterm -> bool |
|
130 val is_disj: cterm -> bool |
|
131 val is_eq: cterm -> bool |
|
132 val is_exists: cterm -> bool |
|
133 val is_forall: cterm -> bool |
|
134 val is_imp: cterm -> bool |
|
135 val is_neg: cterm -> bool |
|
136 val is_pair: cterm -> bool |
|
137 val list_mk_disj: cterm list -> cterm |
|
138 val strip_abs: cterm -> cterm list * cterm |
|
139 val strip_comb: cterm -> cterm * cterm list |
|
140 val strip_disj: cterm -> cterm list |
|
141 val strip_exists: cterm -> cterm list * cterm |
|
142 val strip_forall: cterm -> cterm list * cterm |
|
143 val strip_imp: cterm -> cterm list * cterm |
|
144 val drop_prop: cterm -> cterm |
|
145 val mk_prop: cterm -> cterm |
|
146 end; |
|
147 |
|
148 signature RULES = |
|
149 sig |
|
150 val dest_thm: thm -> term list * term |
|
151 |
|
152 (* Inference rules *) |
|
153 val REFL: cterm -> thm |
|
154 val ASSUME: cterm -> thm |
|
155 val MP: thm -> thm -> thm |
|
156 val MATCH_MP: thm -> thm -> thm |
|
157 val CONJUNCT1: thm -> thm |
|
158 val CONJUNCT2: thm -> thm |
|
159 val CONJUNCTS: thm -> thm list |
|
160 val DISCH: cterm -> thm -> thm |
|
161 val UNDISCH: thm -> thm |
|
162 val SPEC: cterm -> thm -> thm |
|
163 val ISPEC: cterm -> thm -> thm |
|
164 val ISPECL: cterm list -> thm -> thm |
|
165 val GEN: Proof.context -> cterm -> thm -> thm |
|
166 val GENL: Proof.context -> cterm list -> thm -> thm |
|
167 val LIST_CONJ: thm list -> thm |
|
168 |
|
169 val SYM: thm -> thm |
|
170 val DISCH_ALL: thm -> thm |
|
171 val FILTER_DISCH_ALL: (term -> bool) -> thm -> thm |
|
172 val SPEC_ALL: thm -> thm |
|
173 val GEN_ALL: Proof.context -> thm -> thm |
|
174 val IMP_TRANS: thm -> thm -> thm |
|
175 val PROVE_HYP: thm -> thm -> thm |
|
176 |
|
177 val CHOOSE: Proof.context -> cterm * thm -> thm -> thm |
|
178 val EXISTS: cterm * cterm -> thm -> thm |
|
179 val EXISTL: cterm list -> thm -> thm |
|
180 val IT_EXISTS: Proof.context -> (cterm * cterm) list -> thm -> thm |
|
181 |
|
182 val EVEN_ORS: thm list -> thm list |
|
183 val DISJ_CASESL: thm -> thm list -> thm |
|
184 |
|
185 val list_beta_conv: cterm -> cterm list -> thm |
|
186 val SUBS: Proof.context -> thm list -> thm -> thm |
|
187 val simpl_conv: Proof.context -> thm list -> cterm -> thm |
|
188 |
|
189 val rbeta: thm -> thm |
|
190 val tracing: bool Unsynchronized.ref |
|
191 val CONTEXT_REWRITE_RULE: Proof.context -> |
|
192 term * term list * thm * thm list -> thm -> thm * term list |
|
193 val RIGHT_ASSOC: Proof.context -> thm -> thm |
|
194 |
|
195 val prove: Proof.context -> bool -> term * tactic -> thm |
|
196 end; |
|
197 |
|
198 signature THRY = |
|
199 sig |
|
200 val match_term: theory -> term -> term -> (term * term) list * (typ * typ) list |
|
201 val match_type: theory -> typ -> typ -> (typ * typ) list |
|
202 val typecheck: theory -> term -> cterm |
|
203 (*datatype facts of various flavours*) |
|
204 val match_info: theory -> string -> {constructors: term list, case_const: term} option |
|
205 val induct_info: theory -> string -> {constructors: term list, nchotomy: thm} option |
|
206 val extract_info: theory -> {case_congs: thm list, case_rewrites: thm list} |
|
207 end; |
|
208 |
|
209 signature PRIM = |
|
210 sig |
|
211 val trace: bool Unsynchronized.ref |
|
212 val trace_thms: Proof.context -> string -> thm list -> unit |
|
213 val trace_cterm: Proof.context -> string -> cterm -> unit |
|
214 type pattern |
|
215 val mk_functional: theory -> term list -> {functional: term, pats: pattern list} |
|
216 val wfrec_definition0: string -> term -> term -> theory -> thm * theory |
|
217 val post_definition: Proof.context -> thm list -> thm * pattern list -> |
|
218 {rules: thm, |
|
219 rows: int list, |
|
220 TCs: term list list, |
|
221 full_pats_TCs: (term * term list) list} |
|
222 val wfrec_eqns: theory -> xstring -> thm list -> term list -> |
|
223 {WFR: term, |
|
224 SV: term list, |
|
225 proto_def: term, |
|
226 extracta: (thm * term list) list, |
|
227 pats: pattern list} |
|
228 val lazyR_def: theory -> xstring -> thm list -> term list -> |
|
229 {theory: theory, |
|
230 rules: thm, |
|
231 R: term, |
|
232 SV: term list, |
|
233 full_pats_TCs: (term * term list) list, |
|
234 patterns : pattern list} |
|
235 val mk_induction: theory -> |
|
236 {fconst: term, R: term, SV: term list, pat_TCs_list: (term * term list) list} -> thm |
|
237 val postprocess: Proof.context -> bool -> |
|
238 {wf_tac: tactic, terminator: tactic, simplifier: cterm -> thm} -> |
|
239 {rules: thm, induction: thm, TCs: term list list} -> |
|
240 {rules: thm, induction: thm, nested_tcs: thm list} |
|
241 end; |
|
242 |
|
243 signature TFL = |
|
244 sig |
|
245 val define_i: bool -> thm list -> thm list -> xstring -> term -> term list -> Proof.context -> |
|
246 {lhs: term, rules: (thm * int) list, induct: thm, tcs: term list} * Proof.context |
|
247 val define: bool -> thm list -> thm list -> xstring -> string -> string list -> Proof.context -> |
|
248 {lhs: term, rules: (thm * int) list, induct: thm, tcs: term list} * Proof.context |
|
249 val defer_i: thm list -> xstring -> term list -> theory -> thm * theory |
|
250 val defer: thm list -> xstring -> string list -> theory -> thm * theory |
|
251 end; |
|
252 |
|
253 signature OLD_RECDEF = |
|
254 sig |
|
255 val get_recdef: theory -> string |
|
256 -> {lhs: term, simps: thm list, rules: thm list list, induct: thm, tcs: term list} option |
|
257 val get_hints: Proof.context -> {simps: thm list, congs: (string * thm) list, wfs: thm list} |
|
258 val simp_add: attribute |
|
259 val simp_del: attribute |
|
260 val cong_add: attribute |
|
261 val cong_del: attribute |
|
262 val wf_add: attribute |
|
263 val wf_del: attribute |
|
264 val add_recdef: bool -> xstring -> string -> ((binding * string) * Token.src list) list -> |
|
265 Token.src option -> theory -> theory |
|
266 * {lhs: term, simps: thm list, rules: thm list list, induct: thm, tcs: term list} |
|
267 val add_recdef_i: bool -> xstring -> term -> ((binding * term) * attribute list) list -> |
|
268 theory -> theory * {lhs: term, simps: thm list, rules: thm list list, induct: thm, tcs: term list} |
|
269 val defer_recdef: xstring -> string list -> (Facts.ref * Token.src list) list |
|
270 -> theory -> theory * {induct_rules: thm} |
|
271 val defer_recdef_i: xstring -> term list -> thm list -> theory -> theory * {induct_rules: thm} |
|
272 val recdef_tc: bstring * Token.src list -> xstring -> int option -> bool -> |
|
273 local_theory -> Proof.state |
|
274 val recdef_tc_i: bstring * Token.src list -> string -> int option -> bool -> |
|
275 local_theory -> Proof.state |
|
276 end; |
|
277 |
|
278 structure Old_Recdef: OLD_RECDEF = |
|
279 struct |
|
280 |
|
281 (*** extra case splitting for TFL ***) |
|
282 |
|
283 structure CaseSplit: CASE_SPLIT = |
|
284 struct |
|
285 |
|
286 (* make a casethm from an induction thm *) |
|
287 val cases_thm_of_induct_thm = |
|
288 Seq.hd o (ALLGOALS (fn i => REPEAT (etac Drule.thin_rl i))); |
|
289 |
|
290 (* get the case_thm (my version) from a type *) |
|
291 fun case_thm_of_ty thy ty = |
|
292 let |
|
293 val ty_str = case ty of |
|
294 Type(ty_str, _) => ty_str |
|
295 | TFree(s,_) => error ("Free type: " ^ s) |
|
296 | TVar((s,i),_) => error ("Free variable: " ^ s) |
|
297 val {induct, ...} = BNF_LFP_Compat.the_info thy [BNF_LFP_Compat.Keep_Nesting] ty_str |
|
298 in |
|
299 cases_thm_of_induct_thm induct |
|
300 end; |
|
301 |
|
302 |
|
303 (* for use when there are no prems to the subgoal *) |
|
304 (* does a case split on the given variable *) |
|
305 fun mk_casesplit_goal_thm ctxt (vstr,ty) gt = |
|
306 let |
|
307 val thy = Proof_Context.theory_of ctxt; |
|
308 |
|
309 val x = Free(vstr,ty); |
|
310 val abst = Abs(vstr, ty, Term.abstract_over (x, gt)); |
|
311 |
|
312 val case_thm = case_thm_of_ty thy ty; |
|
313 |
|
314 val abs_ct = Thm.cterm_of ctxt abst; |
|
315 val free_ct = Thm.cterm_of ctxt x; |
|
316 |
|
317 val (Pv, Dv, type_insts) = |
|
318 case (Thm.concl_of case_thm) of |
|
319 (_ $ (Pv $ (Dv as Var(D, Dty)))) => |
|
320 (Pv, Dv, |
|
321 Sign.typ_match thy (Dty, ty) Vartab.empty) |
|
322 | _ => error "not a valid case thm"; |
|
323 val type_cinsts = map (fn (ixn, (S, T)) => apply2 (Thm.ctyp_of ctxt) (TVar (ixn, S), T)) |
|
324 (Vartab.dest type_insts); |
|
325 val cPv = Thm.cterm_of ctxt (Envir.subst_term_types type_insts Pv); |
|
326 val cDv = Thm.cterm_of ctxt (Envir.subst_term_types type_insts Dv); |
|
327 in |
|
328 Conv.fconv_rule Drule.beta_eta_conversion |
|
329 (case_thm |
|
330 |> Thm.instantiate (type_cinsts, []) |
|
331 |> Thm.instantiate ([], [(cPv, abs_ct), (cDv, free_ct)])) |
|
332 end; |
|
333 |
|
334 |
|
335 (* the find_XXX_split functions are simply doing a lightwieght (I |
|
336 think) term matching equivalent to find where to do the next split *) |
|
337 |
|
338 (* assuming two twems are identical except for a free in one at a |
|
339 subterm, or constant in another, ie assume that one term is a plit of |
|
340 another, then gives back the free variable that has been split. *) |
|
341 exception find_split_exp of string |
|
342 fun find_term_split (Free v, _ $ _) = SOME v |
|
343 | find_term_split (Free v, Const _) = SOME v |
|
344 | find_term_split (Free v, Abs _) = SOME v (* do we really want this case? *) |
|
345 | find_term_split (Free v, Var _) = NONE (* keep searching *) |
|
346 | find_term_split (a $ b, a2 $ b2) = |
|
347 (case find_term_split (a, a2) of |
|
348 NONE => find_term_split (b,b2) |
|
349 | vopt => vopt) |
|
350 | find_term_split (Abs(_,ty,t1), Abs(_,ty2,t2)) = |
|
351 find_term_split (t1, t2) |
|
352 | find_term_split (Const (x,ty), Const(x2,ty2)) = |
|
353 if x = x2 then NONE else (* keep searching *) |
|
354 raise find_split_exp (* stop now *) |
|
355 "Terms are not identical upto a free varaible! (Consts)" |
|
356 | find_term_split (Bound i, Bound j) = |
|
357 if i = j then NONE else (* keep searching *) |
|
358 raise find_split_exp (* stop now *) |
|
359 "Terms are not identical upto a free varaible! (Bound)" |
|
360 | find_term_split _ = |
|
361 raise find_split_exp (* stop now *) |
|
362 "Terms are not identical upto a free varaible! (Other)"; |
|
363 |
|
364 (* assume that "splitth" is a case split form of subgoal i of "genth", |
|
365 then look for a free variable to split, breaking the subgoal closer to |
|
366 splitth. *) |
|
367 fun find_thm_split splitth i genth = |
|
368 find_term_split (Logic.get_goal (Thm.prop_of genth) i, |
|
369 Thm.concl_of splitth) handle find_split_exp _ => NONE; |
|
370 |
|
371 (* as above but searches "splitths" for a theorem that suggest a case split *) |
|
372 fun find_thms_split splitths i genth = |
|
373 Library.get_first (fn sth => find_thm_split sth i genth) splitths; |
|
374 |
|
375 |
|
376 (* split the subgoal i of "genth" until we get to a member of |
|
377 splitths. Assumes that genth will be a general form of splitths, that |
|
378 can be case-split, as needed. Otherwise fails. Note: We assume that |
|
379 all of "splitths" are split to the same level, and thus it doesn't |
|
380 matter which one we choose to look for the next split. Simply add |
|
381 search on splitthms and split variable, to change this. *) |
|
382 (* Note: possible efficiency measure: when a case theorem is no longer |
|
383 useful, drop it? *) |
|
384 (* Note: This should not be a separate tactic but integrated into the |
|
385 case split done during recdef's case analysis, this would avoid us |
|
386 having to (re)search for variables to split. *) |
|
387 fun splitto ctxt splitths genth = |
|
388 let |
|
389 val _ = not (null splitths) orelse error "splitto: no given splitths"; |
|
390 |
|
391 (* check if we are a member of splitths - FIXME: quicker and |
|
392 more flexible with discrim net. *) |
|
393 fun solve_by_splitth th split = |
|
394 Thm.biresolution (SOME ctxt) false [(false,split)] 1 th; |
|
395 |
|
396 fun split th = |
|
397 (case find_thms_split splitths 1 th of |
|
398 NONE => |
|
399 (writeln (cat_lines |
|
400 (["th:", Display.string_of_thm ctxt th, "split ths:"] @ |
|
401 map (Display.string_of_thm ctxt) splitths @ ["\n--"])); |
|
402 error "splitto: cannot find variable to split on") |
|
403 | SOME v => |
|
404 let |
|
405 val gt = HOLogic.dest_Trueprop (#1 (Logic.dest_implies (Thm.prop_of th))); |
|
406 val split_thm = mk_casesplit_goal_thm ctxt v gt; |
|
407 val (subthms, expf) = IsaND.fixed_subgoal_thms ctxt split_thm; |
|
408 in |
|
409 expf (map recsplitf subthms) |
|
410 end) |
|
411 |
|
412 and recsplitf th = |
|
413 (* note: multiple unifiers! we only take the first element, |
|
414 probably fine -- there is probably only one anyway. *) |
|
415 (case get_first (Seq.pull o solve_by_splitth th) splitths of |
|
416 NONE => split th |
|
417 | SOME (solved_th, _) => solved_th); |
|
418 in |
|
419 recsplitf genth |
|
420 end; |
|
421 |
|
422 end; |
|
423 |
|
424 |
|
425 (*** basic utilities ***) |
|
426 |
|
427 structure Utils: UTILS = |
|
428 struct |
|
429 |
|
430 (*standard exception for TFL*) |
|
431 exception ERR of {module: string, func: string, mesg: string}; |
|
432 |
|
433 fun UTILS_ERR func mesg = ERR {module = "Utils", func = func, mesg = mesg}; |
|
434 |
|
435 |
|
436 fun end_itlist f [] = raise (UTILS_ERR "end_itlist" "list too short") |
|
437 | end_itlist f [x] = x |
|
438 | end_itlist f (x :: xs) = f x (end_itlist f xs); |
|
439 |
|
440 fun itlist2 f L1 L2 base_value = |
|
441 let fun it ([],[]) = base_value |
|
442 | it ((a::rst1),(b::rst2)) = f a b (it (rst1,rst2)) |
|
443 | it _ = raise UTILS_ERR "itlist2" "different length lists" |
|
444 in it (L1,L2) |
|
445 end; |
|
446 |
|
447 fun pluck p = |
|
448 let fun remv ([],_) = raise UTILS_ERR "pluck" "item not found" |
|
449 | remv (h::t, A) = if p h then (h, rev A @ t) else remv (t,h::A) |
|
450 in fn L => remv(L,[]) |
|
451 end; |
|
452 |
|
453 fun take f = |
|
454 let fun grab(0,L) = [] |
|
455 | grab(n, x::rst) = f x::grab(n-1,rst) |
|
456 in grab |
|
457 end; |
|
458 |
|
459 fun zip3 [][][] = [] |
|
460 | zip3 (x::l1) (y::l2) (z::l3) = (x,y,z)::zip3 l1 l2 l3 |
|
461 | zip3 _ _ _ = raise UTILS_ERR "zip3" "different lengths"; |
|
462 |
|
463 |
|
464 end; |
|
465 |
|
466 |
|
467 (*** emulation of HOL's abstract syntax functions ***) |
|
468 |
|
469 structure USyntax: USYNTAX = |
|
470 struct |
|
471 |
|
472 infix 4 ##; |
|
473 |
|
474 fun USYN_ERR func mesg = Utils.ERR {module = "USyntax", func = func, mesg = mesg}; |
|
475 |
|
476 |
|
477 (*--------------------------------------------------------------------------- |
|
478 * |
|
479 * Types |
|
480 * |
|
481 *---------------------------------------------------------------------------*) |
|
482 val mk_prim_vartype = TVar; |
|
483 fun mk_vartype s = mk_prim_vartype ((s, 0), @{sort type}); |
|
484 |
|
485 (* But internally, it's useful *) |
|
486 fun dest_vtype (TVar x) = x |
|
487 | dest_vtype _ = raise USYN_ERR "dest_vtype" "not a flexible type variable"; |
|
488 |
|
489 val is_vartype = can dest_vtype; |
|
490 |
|
491 val type_vars = map mk_prim_vartype o Misc_Legacy.typ_tvars |
|
492 fun type_varsl L = distinct (op =) (fold (curry op @ o type_vars) L []); |
|
493 |
|
494 val alpha = mk_vartype "'a" |
|
495 val beta = mk_vartype "'b" |
|
496 |
|
497 val strip_prod_type = HOLogic.flatten_tupleT; |
|
498 |
|
499 |
|
500 |
|
501 (*--------------------------------------------------------------------------- |
|
502 * |
|
503 * Terms |
|
504 * |
|
505 *---------------------------------------------------------------------------*) |
|
506 |
|
507 (* Free variables, in order of occurrence, from left to right in the |
|
508 * syntax tree. *) |
|
509 fun free_vars_lr tm = |
|
510 let fun memb x = let fun m[] = false | m(y::rst) = (x=y)orelse m rst in m end |
|
511 fun add (t, frees) = case t of |
|
512 Free _ => if (memb t frees) then frees else t::frees |
|
513 | Abs (_,_,body) => add(body,frees) |
|
514 | f$t => add(t, add(f, frees)) |
|
515 | _ => frees |
|
516 in rev(add(tm,[])) |
|
517 end; |
|
518 |
|
519 |
|
520 |
|
521 val type_vars_in_term = map mk_prim_vartype o Misc_Legacy.term_tvars; |
|
522 |
|
523 |
|
524 |
|
525 (* Prelogic *) |
|
526 fun dest_tybinding (v,ty) = (#1(dest_vtype v),ty) |
|
527 fun inst theta = subst_vars (map dest_tybinding theta,[]) |
|
528 |
|
529 |
|
530 (* Construction routines *) |
|
531 |
|
532 fun mk_abs{Bvar as Var((s,_),ty),Body} = Abs(s,ty,abstract_over(Bvar,Body)) |
|
533 | mk_abs{Bvar as Free(s,ty),Body} = Abs(s,ty,abstract_over(Bvar,Body)) |
|
534 | mk_abs _ = raise USYN_ERR "mk_abs" "Bvar is not a variable"; |
|
535 |
|
536 |
|
537 fun mk_imp{ant,conseq} = |
|
538 let val c = Const(@{const_name HOL.implies},HOLogic.boolT --> HOLogic.boolT --> HOLogic.boolT) |
|
539 in list_comb(c,[ant,conseq]) |
|
540 end; |
|
541 |
|
542 fun mk_select (r as {Bvar,Body}) = |
|
543 let val ty = type_of Bvar |
|
544 val c = Const(@{const_name Eps},(ty --> HOLogic.boolT) --> ty) |
|
545 in list_comb(c,[mk_abs r]) |
|
546 end; |
|
547 |
|
548 fun mk_forall (r as {Bvar,Body}) = |
|
549 let val ty = type_of Bvar |
|
550 val c = Const(@{const_name All},(ty --> HOLogic.boolT) --> HOLogic.boolT) |
|
551 in list_comb(c,[mk_abs r]) |
|
552 end; |
|
553 |
|
554 fun mk_exists (r as {Bvar,Body}) = |
|
555 let val ty = type_of Bvar |
|
556 val c = Const(@{const_name Ex},(ty --> HOLogic.boolT) --> HOLogic.boolT) |
|
557 in list_comb(c,[mk_abs r]) |
|
558 end; |
|
559 |
|
560 |
|
561 fun mk_conj{conj1,conj2} = |
|
562 let val c = Const(@{const_name HOL.conj},HOLogic.boolT --> HOLogic.boolT --> HOLogic.boolT) |
|
563 in list_comb(c,[conj1,conj2]) |
|
564 end; |
|
565 |
|
566 fun mk_disj{disj1,disj2} = |
|
567 let val c = Const(@{const_name HOL.disj},HOLogic.boolT --> HOLogic.boolT --> HOLogic.boolT) |
|
568 in list_comb(c,[disj1,disj2]) |
|
569 end; |
|
570 |
|
571 fun prod_ty ty1 ty2 = HOLogic.mk_prodT (ty1,ty2); |
|
572 |
|
573 local |
|
574 fun mk_uncurry (xt, yt, zt) = |
|
575 Const(@{const_name case_prod}, (xt --> yt --> zt) --> prod_ty xt yt --> zt) |
|
576 fun dest_pair(Const(@{const_name Pair},_) $ M $ N) = {fst=M, snd=N} |
|
577 | dest_pair _ = raise USYN_ERR "dest_pair" "not a pair" |
|
578 fun is_var (Var _) = true | is_var (Free _) = true | is_var _ = false |
|
579 in |
|
580 fun mk_pabs{varstruct,body} = |
|
581 let fun mpa (varstruct, body) = |
|
582 if is_var varstruct |
|
583 then mk_abs {Bvar = varstruct, Body = body} |
|
584 else let val {fst, snd} = dest_pair varstruct |
|
585 in mk_uncurry (type_of fst, type_of snd, type_of body) $ |
|
586 mpa (fst, mpa (snd, body)) |
|
587 end |
|
588 in mpa (varstruct, body) end |
|
589 handle TYPE _ => raise USYN_ERR "mk_pabs" ""; |
|
590 end; |
|
591 |
|
592 (* Destruction routines *) |
|
593 |
|
594 datatype lambda = VAR of {Name : string, Ty : typ} |
|
595 | CONST of {Name : string, Ty : typ} |
|
596 | COMB of {Rator: term, Rand : term} |
|
597 | LAMB of {Bvar : term, Body : term}; |
|
598 |
|
599 |
|
600 fun dest_term(Var((s,i),ty)) = VAR{Name = s, Ty = ty} |
|
601 | dest_term(Free(s,ty)) = VAR{Name = s, Ty = ty} |
|
602 | dest_term(Const(s,ty)) = CONST{Name = s, Ty = ty} |
|
603 | dest_term(M$N) = COMB{Rator=M,Rand=N} |
|
604 | dest_term(Abs(s,ty,M)) = let val v = Free(s,ty) |
|
605 in LAMB{Bvar = v, Body = Term.betapply (M,v)} |
|
606 end |
|
607 | dest_term(Bound _) = raise USYN_ERR "dest_term" "Bound"; |
|
608 |
|
609 fun dest_const(Const(s,ty)) = {Name = s, Ty = ty} |
|
610 | dest_const _ = raise USYN_ERR "dest_const" "not a constant"; |
|
611 |
|
612 fun dest_comb(t1 $ t2) = {Rator = t1, Rand = t2} |
|
613 | dest_comb _ = raise USYN_ERR "dest_comb" "not a comb"; |
|
614 |
|
615 fun dest_abs used (a as Abs(s, ty, M)) = |
|
616 let |
|
617 val s' = singleton (Name.variant_list used) s; |
|
618 val v = Free(s', ty); |
|
619 in ({Bvar = v, Body = Term.betapply (a,v)}, s'::used) |
|
620 end |
|
621 | dest_abs _ _ = raise USYN_ERR "dest_abs" "not an abstraction"; |
|
622 |
|
623 fun dest_eq(Const(@{const_name HOL.eq},_) $ M $ N) = {lhs=M, rhs=N} |
|
624 | dest_eq _ = raise USYN_ERR "dest_eq" "not an equality"; |
|
625 |
|
626 fun dest_imp(Const(@{const_name HOL.implies},_) $ M $ N) = {ant=M, conseq=N} |
|
627 | dest_imp _ = raise USYN_ERR "dest_imp" "not an implication"; |
|
628 |
|
629 fun dest_forall(Const(@{const_name All},_) $ (a as Abs _)) = fst (dest_abs [] a) |
|
630 | dest_forall _ = raise USYN_ERR "dest_forall" "not a forall"; |
|
631 |
|
632 fun dest_exists(Const(@{const_name Ex},_) $ (a as Abs _)) = fst (dest_abs [] a) |
|
633 | dest_exists _ = raise USYN_ERR "dest_exists" "not an existential"; |
|
634 |
|
635 fun dest_neg(Const(@{const_name Not},_) $ M) = M |
|
636 | dest_neg _ = raise USYN_ERR "dest_neg" "not a negation"; |
|
637 |
|
638 fun dest_conj(Const(@{const_name HOL.conj},_) $ M $ N) = {conj1=M, conj2=N} |
|
639 | dest_conj _ = raise USYN_ERR "dest_conj" "not a conjunction"; |
|
640 |
|
641 fun dest_disj(Const(@{const_name HOL.disj},_) $ M $ N) = {disj1=M, disj2=N} |
|
642 | dest_disj _ = raise USYN_ERR "dest_disj" "not a disjunction"; |
|
643 |
|
644 fun mk_pair{fst,snd} = |
|
645 let val ty1 = type_of fst |
|
646 val ty2 = type_of snd |
|
647 val c = Const(@{const_name Pair},ty1 --> ty2 --> prod_ty ty1 ty2) |
|
648 in list_comb(c,[fst,snd]) |
|
649 end; |
|
650 |
|
651 fun dest_pair(Const(@{const_name Pair},_) $ M $ N) = {fst=M, snd=N} |
|
652 | dest_pair _ = raise USYN_ERR "dest_pair" "not a pair"; |
|
653 |
|
654 |
|
655 local fun ucheck t = (if #Name (dest_const t) = @{const_name case_prod} then t |
|
656 else raise Match) |
|
657 in |
|
658 fun dest_pabs used tm = |
|
659 let val ({Bvar,Body}, used') = dest_abs used tm |
|
660 in {varstruct = Bvar, body = Body, used = used'} |
|
661 end handle Utils.ERR _ => |
|
662 let val {Rator,Rand} = dest_comb tm |
|
663 val _ = ucheck Rator |
|
664 val {varstruct = lv, body, used = used'} = dest_pabs used Rand |
|
665 val {varstruct = rv, body, used = used''} = dest_pabs used' body |
|
666 in {varstruct = mk_pair {fst = lv, snd = rv}, body = body, used = used''} |
|
667 end |
|
668 end; |
|
669 |
|
670 |
|
671 val lhs = #lhs o dest_eq |
|
672 val rhs = #rhs o dest_eq |
|
673 val rand = #Rand o dest_comb |
|
674 |
|
675 |
|
676 (* Query routines *) |
|
677 val is_imp = can dest_imp |
|
678 val is_forall = can dest_forall |
|
679 val is_exists = can dest_exists |
|
680 val is_neg = can dest_neg |
|
681 val is_conj = can dest_conj |
|
682 val is_disj = can dest_disj |
|
683 val is_pair = can dest_pair |
|
684 val is_pabs = can (dest_pabs []) |
|
685 |
|
686 |
|
687 (* Construction of a cterm from a list of Terms *) |
|
688 |
|
689 fun list_mk_abs(L,tm) = fold_rev (fn v => fn M => mk_abs{Bvar=v, Body=M}) L tm; |
|
690 |
|
691 (* These others are almost never used *) |
|
692 fun list_mk_imp(A,c) = fold_rev (fn a => fn tm => mk_imp{ant=a,conseq=tm}) A c; |
|
693 fun list_mk_forall(V,t) = fold_rev (fn v => fn b => mk_forall{Bvar=v, Body=b})V t; |
|
694 val list_mk_conj = Utils.end_itlist(fn c1 => fn tm => mk_conj{conj1=c1, conj2=tm}) |
|
695 |
|
696 |
|
697 (* Need to reverse? *) |
|
698 fun gen_all tm = list_mk_forall(Misc_Legacy.term_frees tm, tm); |
|
699 |
|
700 (* Destructing a cterm to a list of Terms *) |
|
701 fun strip_comb tm = |
|
702 let fun dest(M$N, A) = dest(M, N::A) |
|
703 | dest x = x |
|
704 in dest(tm,[]) |
|
705 end; |
|
706 |
|
707 fun strip_abs(tm as Abs _) = |
|
708 let val ({Bvar,Body}, _) = dest_abs [] tm |
|
709 val (bvs, core) = strip_abs Body |
|
710 in (Bvar::bvs, core) |
|
711 end |
|
712 | strip_abs M = ([],M); |
|
713 |
|
714 |
|
715 fun strip_imp fm = |
|
716 if (is_imp fm) |
|
717 then let val {ant,conseq} = dest_imp fm |
|
718 val (was,wb) = strip_imp conseq |
|
719 in ((ant::was), wb) |
|
720 end |
|
721 else ([],fm); |
|
722 |
|
723 fun strip_forall fm = |
|
724 if (is_forall fm) |
|
725 then let val {Bvar,Body} = dest_forall fm |
|
726 val (bvs,core) = strip_forall Body |
|
727 in ((Bvar::bvs), core) |
|
728 end |
|
729 else ([],fm); |
|
730 |
|
731 |
|
732 fun strip_exists fm = |
|
733 if (is_exists fm) |
|
734 then let val {Bvar, Body} = dest_exists fm |
|
735 val (bvs,core) = strip_exists Body |
|
736 in (Bvar::bvs, core) |
|
737 end |
|
738 else ([],fm); |
|
739 |
|
740 fun strip_disj w = |
|
741 if (is_disj w) |
|
742 then let val {disj1,disj2} = dest_disj w |
|
743 in (strip_disj disj1@strip_disj disj2) |
|
744 end |
|
745 else [w]; |
|
746 |
|
747 |
|
748 (* Miscellaneous *) |
|
749 |
|
750 fun mk_vstruct ty V = |
|
751 let fun follow_prod_type (Type(@{type_name Product_Type.prod},[ty1,ty2])) vs = |
|
752 let val (ltm,vs1) = follow_prod_type ty1 vs |
|
753 val (rtm,vs2) = follow_prod_type ty2 vs1 |
|
754 in (mk_pair{fst=ltm, snd=rtm}, vs2) end |
|
755 | follow_prod_type _ (v::vs) = (v,vs) |
|
756 in #1 (follow_prod_type ty V) end; |
|
757 |
|
758 |
|
759 (* Search a term for a sub-term satisfying the predicate p. *) |
|
760 fun find_term p = |
|
761 let fun find tm = |
|
762 if (p tm) then SOME tm |
|
763 else case tm of |
|
764 Abs(_,_,body) => find body |
|
765 | (t$u) => (case find t of NONE => find u | some => some) |
|
766 | _ => NONE |
|
767 in find |
|
768 end; |
|
769 |
|
770 fun dest_relation tm = |
|
771 if (type_of tm = HOLogic.boolT) |
|
772 then let val (Const(@{const_name Set.member},_) $ (Const(@{const_name Pair},_)$y$x) $ R) = tm |
|
773 in (R,y,x) |
|
774 end handle Bind => raise USYN_ERR "dest_relation" "unexpected term structure" |
|
775 else raise USYN_ERR "dest_relation" "not a boolean term"; |
|
776 |
|
777 fun is_WFR (Const(@{const_name Wellfounded.wf},_)$_) = true |
|
778 | is_WFR _ = false; |
|
779 |
|
780 fun ARB ty = mk_select{Bvar=Free("v",ty), |
|
781 Body=Const(@{const_name True},HOLogic.boolT)}; |
|
782 |
|
783 end; |
|
784 |
|
785 |
|
786 (*** derived cterm destructors ***) |
|
787 |
|
788 structure Dcterm: DCTERM = |
|
789 struct |
|
790 |
|
791 fun ERR func mesg = Utils.ERR {module = "Dcterm", func = func, mesg = mesg}; |
|
792 |
|
793 |
|
794 fun dest_comb t = Thm.dest_comb t |
|
795 handle CTERM (msg, _) => raise ERR "dest_comb" msg; |
|
796 |
|
797 fun dest_abs a t = Thm.dest_abs a t |
|
798 handle CTERM (msg, _) => raise ERR "dest_abs" msg; |
|
799 |
|
800 fun capply t u = Thm.apply t u |
|
801 handle CTERM (msg, _) => raise ERR "capply" msg; |
|
802 |
|
803 fun cabs a t = Thm.lambda a t |
|
804 handle CTERM (msg, _) => raise ERR "cabs" msg; |
|
805 |
|
806 |
|
807 (*--------------------------------------------------------------------------- |
|
808 * Some simple constructor functions. |
|
809 *---------------------------------------------------------------------------*) |
|
810 |
|
811 val mk_hol_const = Thm.cterm_of @{theory_context HOL} o Const; |
|
812 |
|
813 fun mk_exists (r as (Bvar, Body)) = |
|
814 let val ty = Thm.typ_of_cterm Bvar |
|
815 val c = mk_hol_const(@{const_name Ex}, (ty --> HOLogic.boolT) --> HOLogic.boolT) |
|
816 in capply c (uncurry cabs r) end; |
|
817 |
|
818 |
|
819 local val c = mk_hol_const(@{const_name HOL.conj}, HOLogic.boolT --> HOLogic.boolT --> HOLogic.boolT) |
|
820 in fun mk_conj(conj1,conj2) = capply (capply c conj1) conj2 |
|
821 end; |
|
822 |
|
823 local val c = mk_hol_const(@{const_name HOL.disj}, HOLogic.boolT --> HOLogic.boolT --> HOLogic.boolT) |
|
824 in fun mk_disj(disj1,disj2) = capply (capply c disj1) disj2 |
|
825 end; |
|
826 |
|
827 |
|
828 (*--------------------------------------------------------------------------- |
|
829 * The primitives. |
|
830 *---------------------------------------------------------------------------*) |
|
831 fun dest_const ctm = |
|
832 (case Thm.term_of ctm |
|
833 of Const(s,ty) => {Name = s, Ty = ty} |
|
834 | _ => raise ERR "dest_const" "not a constant"); |
|
835 |
|
836 fun dest_var ctm = |
|
837 (case Thm.term_of ctm |
|
838 of Var((s,i),ty) => {Name=s, Ty=ty} |
|
839 | Free(s,ty) => {Name=s, Ty=ty} |
|
840 | _ => raise ERR "dest_var" "not a variable"); |
|
841 |
|
842 |
|
843 (*--------------------------------------------------------------------------- |
|
844 * Derived destructor operations. |
|
845 *---------------------------------------------------------------------------*) |
|
846 |
|
847 fun dest_monop expected tm = |
|
848 let |
|
849 fun err () = raise ERR "dest_monop" ("Not a(n) " ^ quote expected); |
|
850 val (c, N) = dest_comb tm handle Utils.ERR _ => err (); |
|
851 val name = #Name (dest_const c handle Utils.ERR _ => err ()); |
|
852 in if name = expected then N else err () end; |
|
853 |
|
854 fun dest_binop expected tm = |
|
855 let |
|
856 fun err () = raise ERR "dest_binop" ("Not a(n) " ^ quote expected); |
|
857 val (M, N) = dest_comb tm handle Utils.ERR _ => err () |
|
858 in (dest_monop expected M, N) handle Utils.ERR _ => err () end; |
|
859 |
|
860 fun dest_binder expected tm = |
|
861 dest_abs NONE (dest_monop expected tm) |
|
862 handle Utils.ERR _ => raise ERR "dest_binder" ("Not a(n) " ^ quote expected); |
|
863 |
|
864 |
|
865 val dest_neg = dest_monop @{const_name Not} |
|
866 val dest_pair = dest_binop @{const_name Pair} |
|
867 val dest_eq = dest_binop @{const_name HOL.eq} |
|
868 val dest_imp = dest_binop @{const_name HOL.implies} |
|
869 val dest_conj = dest_binop @{const_name HOL.conj} |
|
870 val dest_disj = dest_binop @{const_name HOL.disj} |
|
871 val dest_select = dest_binder @{const_name Eps} |
|
872 val dest_exists = dest_binder @{const_name Ex} |
|
873 val dest_forall = dest_binder @{const_name All} |
|
874 |
|
875 (* Query routines *) |
|
876 |
|
877 val is_eq = can dest_eq |
|
878 val is_imp = can dest_imp |
|
879 val is_select = can dest_select |
|
880 val is_forall = can dest_forall |
|
881 val is_exists = can dest_exists |
|
882 val is_neg = can dest_neg |
|
883 val is_conj = can dest_conj |
|
884 val is_disj = can dest_disj |
|
885 val is_pair = can dest_pair |
|
886 |
|
887 |
|
888 (*--------------------------------------------------------------------------- |
|
889 * Iterated creation. |
|
890 *---------------------------------------------------------------------------*) |
|
891 val list_mk_disj = Utils.end_itlist (fn d1 => fn tm => mk_disj (d1, tm)); |
|
892 |
|
893 (*--------------------------------------------------------------------------- |
|
894 * Iterated destruction. (To the "right" in a term.) |
|
895 *---------------------------------------------------------------------------*) |
|
896 fun strip break tm = |
|
897 let fun dest (p as (ctm,accum)) = |
|
898 let val (M,N) = break ctm |
|
899 in dest (N, M::accum) |
|
900 end handle Utils.ERR _ => p |
|
901 in dest (tm,[]) |
|
902 end; |
|
903 |
|
904 fun rev2swap (x,l) = (rev l, x); |
|
905 |
|
906 val strip_comb = strip (Library.swap o dest_comb) (* Goes to the "left" *) |
|
907 val strip_imp = rev2swap o strip dest_imp |
|
908 val strip_abs = rev2swap o strip (dest_abs NONE) |
|
909 val strip_forall = rev2swap o strip dest_forall |
|
910 val strip_exists = rev2swap o strip dest_exists |
|
911 |
|
912 val strip_disj = rev o (op::) o strip dest_disj |
|
913 |
|
914 |
|
915 (*--------------------------------------------------------------------------- |
|
916 * Going into and out of prop |
|
917 *---------------------------------------------------------------------------*) |
|
918 |
|
919 fun is_Trueprop ct = |
|
920 (case Thm.term_of ct of |
|
921 Const (@{const_name Trueprop}, _) $ _ => true |
|
922 | _ => false); |
|
923 |
|
924 fun mk_prop ct = if is_Trueprop ct then ct else Thm.apply @{cterm Trueprop} ct; |
|
925 fun drop_prop ct = if is_Trueprop ct then Thm.dest_arg ct else ct; |
|
926 |
|
927 end; |
|
928 |
|
929 |
|
930 (*** notable theorems ***) |
|
931 |
|
932 structure Thms = |
|
933 struct |
|
934 val WFREC_COROLLARY = @{thm tfl_wfrec}; |
|
935 val WF_INDUCTION_THM = @{thm tfl_wf_induct}; |
|
936 val CUT_DEF = @{thm tfl_cut_def}; |
|
937 val eqT = @{thm tfl_eq_True}; |
|
938 val rev_eq_mp = @{thm tfl_rev_eq_mp}; |
|
939 val simp_thm = @{thm tfl_simp_thm}; |
|
940 val P_imp_P_iff_True = @{thm tfl_P_imp_P_iff_True}; |
|
941 val imp_trans = @{thm tfl_imp_trans}; |
|
942 val disj_assoc = @{thm tfl_disj_assoc}; |
|
943 val tfl_disjE = @{thm tfl_disjE}; |
|
944 val choose_thm = @{thm tfl_exE}; |
|
945 end; |
|
946 |
|
947 |
|
948 (*** emulation of HOL inference rules for TFL ***) |
|
949 |
|
950 structure Rules: RULES = |
|
951 struct |
|
952 |
|
953 fun RULES_ERR func mesg = Utils.ERR {module = "Rules", func = func, mesg = mesg}; |
|
954 |
|
955 |
|
956 fun cconcl thm = Dcterm.drop_prop (#prop (Thm.crep_thm thm)); |
|
957 fun chyps thm = map Dcterm.drop_prop (#hyps (Thm.crep_thm thm)); |
|
958 |
|
959 fun dest_thm thm = |
|
960 let val {prop,hyps,...} = Thm.rep_thm thm |
|
961 in (map HOLogic.dest_Trueprop hyps, HOLogic.dest_Trueprop prop) end |
|
962 handle TERM _ => raise RULES_ERR "dest_thm" "missing Trueprop"; |
|
963 |
|
964 |
|
965 (* Inference rules *) |
|
966 |
|
967 (*--------------------------------------------------------------------------- |
|
968 * Equality (one step) |
|
969 *---------------------------------------------------------------------------*) |
|
970 |
|
971 fun REFL tm = Thm.reflexive tm RS meta_eq_to_obj_eq |
|
972 handle THM (msg, _, _) => raise RULES_ERR "REFL" msg; |
|
973 |
|
974 fun SYM thm = thm RS sym |
|
975 handle THM (msg, _, _) => raise RULES_ERR "SYM" msg; |
|
976 |
|
977 fun ALPHA thm ctm1 = |
|
978 let |
|
979 val ctm2 = Thm.cprop_of thm; |
|
980 val ctm2_eq = Thm.reflexive ctm2; |
|
981 val ctm1_eq = Thm.reflexive ctm1; |
|
982 in Thm.equal_elim (Thm.transitive ctm2_eq ctm1_eq) thm end |
|
983 handle THM (msg, _, _) => raise RULES_ERR "ALPHA" msg; |
|
984 |
|
985 fun rbeta th = |
|
986 (case Dcterm.strip_comb (cconcl th) of |
|
987 (_, [l, r]) => Thm.transitive th (Thm.beta_conversion false r) |
|
988 | _ => raise RULES_ERR "rbeta" ""); |
|
989 |
|
990 |
|
991 (*---------------------------------------------------------------------------- |
|
992 * Implication and the assumption list |
|
993 * |
|
994 * Assumptions get stuck on the meta-language assumption list. Implications |
|
995 * are in the object language, so discharging an assumption "A" from theorem |
|
996 * "B" results in something that looks like "A --> B". |
|
997 *---------------------------------------------------------------------------*) |
|
998 |
|
999 fun ASSUME ctm = Thm.assume (Dcterm.mk_prop ctm); |
|
1000 |
|
1001 |
|
1002 (*--------------------------------------------------------------------------- |
|
1003 * Implication in TFL is -->. Meta-language implication (==>) is only used |
|
1004 * in the implementation of some of the inference rules below. |
|
1005 *---------------------------------------------------------------------------*) |
|
1006 fun MP th1 th2 = th2 RS (th1 RS mp) |
|
1007 handle THM (msg, _, _) => raise RULES_ERR "MP" msg; |
|
1008 |
|
1009 (*forces the first argument to be a proposition if necessary*) |
|
1010 fun DISCH tm thm = Thm.implies_intr (Dcterm.mk_prop tm) thm COMP impI |
|
1011 handle THM (msg, _, _) => raise RULES_ERR "DISCH" msg; |
|
1012 |
|
1013 fun DISCH_ALL thm = fold_rev DISCH (#hyps (Thm.crep_thm thm)) thm; |
|
1014 |
|
1015 |
|
1016 fun FILTER_DISCH_ALL P thm = |
|
1017 let fun check tm = P (Thm.term_of tm) |
|
1018 in fold_rev (fn tm => fn th => if check tm then DISCH tm th else th) (chyps thm) thm |
|
1019 end; |
|
1020 |
|
1021 fun UNDISCH thm = |
|
1022 let val tm = Dcterm.mk_prop (#1 (Dcterm.dest_imp (cconcl thm))) |
|
1023 in Thm.implies_elim (thm RS mp) (ASSUME tm) end |
|
1024 handle Utils.ERR _ => raise RULES_ERR "UNDISCH" "" |
|
1025 | THM _ => raise RULES_ERR "UNDISCH" ""; |
|
1026 |
|
1027 fun PROVE_HYP ath bth = MP (DISCH (cconcl ath) bth) ath; |
|
1028 |
|
1029 fun IMP_TRANS th1 th2 = th2 RS (th1 RS Thms.imp_trans) |
|
1030 handle THM (msg, _, _) => raise RULES_ERR "IMP_TRANS" msg; |
|
1031 |
|
1032 |
|
1033 (*---------------------------------------------------------------------------- |
|
1034 * Conjunction |
|
1035 *---------------------------------------------------------------------------*) |
|
1036 |
|
1037 fun CONJUNCT1 thm = thm RS conjunct1 |
|
1038 handle THM (msg, _, _) => raise RULES_ERR "CONJUNCT1" msg; |
|
1039 |
|
1040 fun CONJUNCT2 thm = thm RS conjunct2 |
|
1041 handle THM (msg, _, _) => raise RULES_ERR "CONJUNCT2" msg; |
|
1042 |
|
1043 fun CONJUNCTS th = CONJUNCTS (CONJUNCT1 th) @ CONJUNCTS (CONJUNCT2 th) handle Utils.ERR _ => [th]; |
|
1044 |
|
1045 fun LIST_CONJ [] = raise RULES_ERR "LIST_CONJ" "empty list" |
|
1046 | LIST_CONJ [th] = th |
|
1047 | LIST_CONJ (th :: rst) = MP (MP (conjI COMP (impI RS impI)) th) (LIST_CONJ rst) |
|
1048 handle THM (msg, _, _) => raise RULES_ERR "LIST_CONJ" msg; |
|
1049 |
|
1050 |
|
1051 (*---------------------------------------------------------------------------- |
|
1052 * Disjunction |
|
1053 *---------------------------------------------------------------------------*) |
|
1054 local |
|
1055 val prop = Thm.prop_of disjI1 |
|
1056 val [P,Q] = Misc_Legacy.term_vars prop |
|
1057 val disj1 = Thm.forall_intr (Thm.cterm_of @{context} Q) disjI1 |
|
1058 in |
|
1059 fun DISJ1 thm tm = thm RS (Thm.forall_elim (Dcterm.drop_prop tm) disj1) |
|
1060 handle THM (msg, _, _) => raise RULES_ERR "DISJ1" msg; |
|
1061 end; |
|
1062 |
|
1063 local |
|
1064 val prop = Thm.prop_of disjI2 |
|
1065 val [P,Q] = Misc_Legacy.term_vars prop |
|
1066 val disj2 = Thm.forall_intr (Thm.cterm_of @{context} P) disjI2 |
|
1067 in |
|
1068 fun DISJ2 tm thm = thm RS (Thm.forall_elim (Dcterm.drop_prop tm) disj2) |
|
1069 handle THM (msg, _, _) => raise RULES_ERR "DISJ2" msg; |
|
1070 end; |
|
1071 |
|
1072 |
|
1073 (*---------------------------------------------------------------------------- |
|
1074 * |
|
1075 * A1 |- M1, ..., An |- Mn |
|
1076 * --------------------------------------------------- |
|
1077 * [A1 |- M1 \/ ... \/ Mn, ..., An |- M1 \/ ... \/ Mn] |
|
1078 * |
|
1079 *---------------------------------------------------------------------------*) |
|
1080 |
|
1081 |
|
1082 fun EVEN_ORS thms = |
|
1083 let fun blue ldisjs [] _ = [] |
|
1084 | blue ldisjs (th::rst) rdisjs = |
|
1085 let val tail = tl rdisjs |
|
1086 val rdisj_tl = Dcterm.list_mk_disj tail |
|
1087 in fold_rev DISJ2 ldisjs (DISJ1 th rdisj_tl) |
|
1088 :: blue (ldisjs @ [cconcl th]) rst tail |
|
1089 end handle Utils.ERR _ => [fold_rev DISJ2 ldisjs th] |
|
1090 in blue [] thms (map cconcl thms) end; |
|
1091 |
|
1092 |
|
1093 (*---------------------------------------------------------------------------- |
|
1094 * |
|
1095 * A |- P \/ Q B,P |- R C,Q |- R |
|
1096 * --------------------------------------------------- |
|
1097 * A U B U C |- R |
|
1098 * |
|
1099 *---------------------------------------------------------------------------*) |
|
1100 |
|
1101 fun DISJ_CASES th1 th2 th3 = |
|
1102 let |
|
1103 val c = Dcterm.drop_prop (cconcl th1); |
|
1104 val (disj1, disj2) = Dcterm.dest_disj c; |
|
1105 val th2' = DISCH disj1 th2; |
|
1106 val th3' = DISCH disj2 th3; |
|
1107 in |
|
1108 th3' RS (th2' RS (th1 RS Thms.tfl_disjE)) |
|
1109 handle THM (msg, _, _) => raise RULES_ERR "DISJ_CASES" msg |
|
1110 end; |
|
1111 |
|
1112 |
|
1113 (*----------------------------------------------------------------------------- |
|
1114 * |
|
1115 * |- A1 \/ ... \/ An [A1 |- M, ..., An |- M] |
|
1116 * --------------------------------------------------- |
|
1117 * |- M |
|
1118 * |
|
1119 * Note. The list of theorems may be all jumbled up, so we have to |
|
1120 * first organize it to align with the first argument (the disjunctive |
|
1121 * theorem). |
|
1122 *---------------------------------------------------------------------------*) |
|
1123 |
|
1124 fun organize eq = (* a bit slow - analogous to insertion sort *) |
|
1125 let fun extract a alist = |
|
1126 let fun ex (_,[]) = raise RULES_ERR "organize" "not a permutation.1" |
|
1127 | ex(left,h::t) = if (eq h a) then (h,rev left@t) else ex(h::left,t) |
|
1128 in ex ([],alist) |
|
1129 end |
|
1130 fun place [] [] = [] |
|
1131 | place (a::rst) alist = |
|
1132 let val (item,next) = extract a alist |
|
1133 in item::place rst next |
|
1134 end |
|
1135 | place _ _ = raise RULES_ERR "organize" "not a permutation.2" |
|
1136 in place |
|
1137 end; |
|
1138 |
|
1139 fun DISJ_CASESL disjth thl = |
|
1140 let val c = cconcl disjth |
|
1141 fun eq th atm = |
|
1142 exists (fn t => HOLogic.dest_Trueprop t aconv Thm.term_of atm) (Thm.hyps_of th) |
|
1143 val tml = Dcterm.strip_disj c |
|
1144 fun DL th [] = raise RULES_ERR "DISJ_CASESL" "no cases" |
|
1145 | DL th [th1] = PROVE_HYP th th1 |
|
1146 | DL th [th1,th2] = DISJ_CASES th th1 th2 |
|
1147 | DL th (th1::rst) = |
|
1148 let val tm = #2 (Dcterm.dest_disj (Dcterm.drop_prop(cconcl th))) |
|
1149 in DISJ_CASES th th1 (DL (ASSUME tm) rst) end |
|
1150 in DL disjth (organize eq tml thl) |
|
1151 end; |
|
1152 |
|
1153 |
|
1154 (*---------------------------------------------------------------------------- |
|
1155 * Universals |
|
1156 *---------------------------------------------------------------------------*) |
|
1157 local (* this is fragile *) |
|
1158 val prop = Thm.prop_of spec |
|
1159 val x = hd (tl (Misc_Legacy.term_vars prop)) |
|
1160 val cTV = Thm.ctyp_of @{context} (type_of x) |
|
1161 val gspec = Thm.forall_intr (Thm.cterm_of @{context} x) spec |
|
1162 in |
|
1163 fun SPEC tm thm = |
|
1164 let val gspec' = Drule.instantiate_normalize ([(cTV, Thm.ctyp_of_cterm tm)], []) gspec |
|
1165 in thm RS (Thm.forall_elim tm gspec') end |
|
1166 end; |
|
1167 |
|
1168 fun SPEC_ALL thm = fold SPEC (#1 (Dcterm.strip_forall(cconcl thm))) thm; |
|
1169 |
|
1170 val ISPEC = SPEC |
|
1171 val ISPECL = fold ISPEC; |
|
1172 |
|
1173 (* Not optimized! Too complicated. *) |
|
1174 local |
|
1175 val prop = Thm.prop_of allI |
|
1176 val [P] = Misc_Legacy.add_term_vars (prop, []) |
|
1177 fun cty_theta ctxt = map (fn (i, (S, ty)) => apply2 (Thm.ctyp_of ctxt) (TVar (i, S), ty)) |
|
1178 fun ctm_theta ctxt = |
|
1179 map (fn (i, (_, tm2)) => |
|
1180 let val ctm2 = Thm.cterm_of ctxt tm2 |
|
1181 in (Thm.cterm_of ctxt (Var (i, Thm.typ_of_cterm ctm2)), ctm2) end) |
|
1182 fun certify ctxt (ty_theta,tm_theta) = |
|
1183 (cty_theta ctxt (Vartab.dest ty_theta), |
|
1184 ctm_theta ctxt (Vartab.dest tm_theta)) |
|
1185 in |
|
1186 fun GEN ctxt v th = |
|
1187 let val gth = Thm.forall_intr v th |
|
1188 val thy = Proof_Context.theory_of ctxt |
|
1189 val Const(@{const_name Pure.all},_)$Abs(x,ty,rst) = Thm.prop_of gth |
|
1190 val P' = Abs(x,ty, HOLogic.dest_Trueprop rst) (* get rid of trueprop *) |
|
1191 val theta = Pattern.match thy (P,P') (Vartab.empty, Vartab.empty); |
|
1192 val allI2 = Drule.instantiate_normalize (certify ctxt theta) allI |
|
1193 val thm = Thm.implies_elim allI2 gth |
|
1194 val tp $ (A $ Abs(_,_,M)) = Thm.prop_of thm |
|
1195 val prop' = tp $ (A $ Abs(x,ty,M)) |
|
1196 in ALPHA thm (Thm.cterm_of ctxt prop') end |
|
1197 end; |
|
1198 |
|
1199 fun GENL ctxt = fold_rev (GEN ctxt); |
|
1200 |
|
1201 fun GEN_ALL ctxt thm = |
|
1202 let |
|
1203 val prop = Thm.prop_of thm |
|
1204 val vlist = map (Thm.cterm_of ctxt) (Misc_Legacy.add_term_vars (prop, [])) |
|
1205 in GENL ctxt vlist thm end; |
|
1206 |
|
1207 |
|
1208 fun MATCH_MP th1 th2 = |
|
1209 if (Dcterm.is_forall (Dcterm.drop_prop(cconcl th1))) |
|
1210 then MATCH_MP (th1 RS spec) th2 |
|
1211 else MP th1 th2; |
|
1212 |
|
1213 |
|
1214 (*---------------------------------------------------------------------------- |
|
1215 * Existentials |
|
1216 *---------------------------------------------------------------------------*) |
|
1217 |
|
1218 |
|
1219 |
|
1220 (*--------------------------------------------------------------------------- |
|
1221 * Existential elimination |
|
1222 * |
|
1223 * A1 |- ?x.t[x] , A2, "t[v]" |- t' |
|
1224 * ------------------------------------ (variable v occurs nowhere) |
|
1225 * A1 u A2 |- t' |
|
1226 * |
|
1227 *---------------------------------------------------------------------------*) |
|
1228 |
|
1229 fun CHOOSE ctxt (fvar, exth) fact = |
|
1230 let |
|
1231 val lam = #2 (Dcterm.dest_comb (Dcterm.drop_prop (cconcl exth))) |
|
1232 val redex = Dcterm.capply lam fvar |
|
1233 val t$u = Thm.term_of redex |
|
1234 val residue = Thm.cterm_of ctxt (Term.betapply (t, u)) |
|
1235 in |
|
1236 GEN ctxt fvar (DISCH residue fact) RS (exth RS Thms.choose_thm) |
|
1237 handle THM (msg, _, _) => raise RULES_ERR "CHOOSE" msg |
|
1238 end; |
|
1239 |
|
1240 local |
|
1241 val prop = Thm.prop_of exI |
|
1242 val [P, x] = map (Thm.cterm_of @{context}) (Misc_Legacy.term_vars prop) |
|
1243 in |
|
1244 fun EXISTS (template,witness) thm = |
|
1245 let val abstr = #2 (Dcterm.dest_comb template) in |
|
1246 thm RS (cterm_instantiate [(P, abstr), (x, witness)] exI) |
|
1247 handle THM (msg, _, _) => raise RULES_ERR "EXISTS" msg |
|
1248 end |
|
1249 end; |
|
1250 |
|
1251 (*---------------------------------------------------------------------------- |
|
1252 * |
|
1253 * A |- M |
|
1254 * ------------------- [v_1,...,v_n] |
|
1255 * A |- ?v1...v_n. M |
|
1256 * |
|
1257 *---------------------------------------------------------------------------*) |
|
1258 |
|
1259 fun EXISTL vlist th = |
|
1260 fold_rev (fn v => fn thm => EXISTS(Dcterm.mk_exists(v,cconcl thm), v) thm) |
|
1261 vlist th; |
|
1262 |
|
1263 |
|
1264 (*---------------------------------------------------------------------------- |
|
1265 * |
|
1266 * A |- M[x_1,...,x_n] |
|
1267 * ---------------------------- [(x |-> y)_1,...,(x |-> y)_n] |
|
1268 * A |- ?y_1...y_n. M |
|
1269 * |
|
1270 *---------------------------------------------------------------------------*) |
|
1271 (* Could be improved, but needs "subst_free" for certified terms *) |
|
1272 |
|
1273 fun IT_EXISTS ctxt blist th = |
|
1274 let |
|
1275 val blist' = map (apply2 Thm.term_of) blist |
|
1276 fun ex v M = Thm.cterm_of ctxt (USyntax.mk_exists{Bvar=v,Body = M}) |
|
1277 in |
|
1278 fold_rev (fn (b as (r1,r2)) => fn thm => |
|
1279 EXISTS(ex r2 (subst_free [b] |
|
1280 (HOLogic.dest_Trueprop(Thm.prop_of thm))), Thm.cterm_of ctxt r1) |
|
1281 thm) |
|
1282 blist' th |
|
1283 end; |
|
1284 |
|
1285 (*--------------------------------------------------------------------------- |
|
1286 * Faster version, that fails for some as yet unknown reason |
|
1287 * fun IT_EXISTS blist th = |
|
1288 * let val {thy,...} = rep_thm th |
|
1289 * val tych = cterm_of thy |
|
1290 * fun detype (x,y) = ((#t o rep_cterm) x, (#t o rep_cterm) y) |
|
1291 * in |
|
1292 * fold (fn (b as (r1,r2), thm) => |
|
1293 * EXISTS(D.mk_exists(r2, tych(subst_free[detype b](#t(rep_cterm(cconcl thm))))), |
|
1294 * r1) thm) blist th |
|
1295 * end; |
|
1296 *---------------------------------------------------------------------------*) |
|
1297 |
|
1298 (*---------------------------------------------------------------------------- |
|
1299 * Rewriting |
|
1300 *---------------------------------------------------------------------------*) |
|
1301 |
|
1302 fun SUBS ctxt thl = |
|
1303 rewrite_rule ctxt (map (fn th => th RS eq_reflection handle THM _ => th) thl); |
|
1304 |
|
1305 val rew_conv = Raw_Simplifier.rewrite_cterm (true, false, false) (K (K NONE)); |
|
1306 |
|
1307 fun simpl_conv ctxt thl ctm = |
|
1308 rew_conv (ctxt addsimps thl) ctm RS meta_eq_to_obj_eq; |
|
1309 |
|
1310 |
|
1311 fun RIGHT_ASSOC ctxt = rewrite_rule ctxt [Thms.disj_assoc]; |
|
1312 |
|
1313 |
|
1314 |
|
1315 (*--------------------------------------------------------------------------- |
|
1316 * TERMINATION CONDITION EXTRACTION |
|
1317 *---------------------------------------------------------------------------*) |
|
1318 |
|
1319 |
|
1320 (* Object language quantifier, i.e., "!" *) |
|
1321 fun Forall v M = USyntax.mk_forall{Bvar=v, Body=M}; |
|
1322 |
|
1323 |
|
1324 (* Fragile: it's a cong if it is not "R y x ==> cut f R x y = f y" *) |
|
1325 fun is_cong thm = |
|
1326 case (Thm.prop_of thm) of |
|
1327 (Const(@{const_name Pure.imp},_)$(Const(@{const_name Trueprop},_)$ _) $ |
|
1328 (Const(@{const_name Pure.eq},_) $ (Const (@{const_name Wfrec.cut},_) $ f $ R $ a $ x) $ _)) => |
|
1329 false |
|
1330 | _ => true; |
|
1331 |
|
1332 |
|
1333 fun dest_equal(Const (@{const_name Pure.eq},_) $ |
|
1334 (Const (@{const_name Trueprop},_) $ lhs) |
|
1335 $ (Const (@{const_name Trueprop},_) $ rhs)) = {lhs=lhs, rhs=rhs} |
|
1336 | dest_equal(Const (@{const_name Pure.eq},_) $ lhs $ rhs) = {lhs=lhs, rhs=rhs} |
|
1337 | dest_equal tm = USyntax.dest_eq tm; |
|
1338 |
|
1339 fun get_lhs tm = #lhs(dest_equal (HOLogic.dest_Trueprop tm)); |
|
1340 |
|
1341 fun dest_all used (Const(@{const_name Pure.all},_) $ (a as Abs _)) = USyntax.dest_abs used a |
|
1342 | dest_all _ _ = raise RULES_ERR "dest_all" "not a !!"; |
|
1343 |
|
1344 val is_all = can (dest_all []); |
|
1345 |
|
1346 fun strip_all used fm = |
|
1347 if (is_all fm) |
|
1348 then let val ({Bvar, Body}, used') = dest_all used fm |
|
1349 val (bvs, core, used'') = strip_all used' Body |
|
1350 in ((Bvar::bvs), core, used'') |
|
1351 end |
|
1352 else ([], fm, used); |
|
1353 |
|
1354 fun break_all(Const(@{const_name Pure.all},_) $ Abs (_,_,body)) = body |
|
1355 | break_all _ = raise RULES_ERR "break_all" "not a !!"; |
|
1356 |
|
1357 fun list_break_all(Const(@{const_name Pure.all},_) $ Abs (s,ty,body)) = |
|
1358 let val (L,core) = list_break_all body |
|
1359 in ((s,ty)::L, core) |
|
1360 end |
|
1361 | list_break_all tm = ([],tm); |
|
1362 |
|
1363 (*--------------------------------------------------------------------------- |
|
1364 * Rename a term of the form |
|
1365 * |
|
1366 * !!x1 ...xn. x1=M1 ==> ... ==> xn=Mn |
|
1367 * ==> ((%v1...vn. Q) x1 ... xn = g x1 ... xn. |
|
1368 * to one of |
|
1369 * |
|
1370 * !!v1 ... vn. v1=M1 ==> ... ==> vn=Mn |
|
1371 * ==> ((%v1...vn. Q) v1 ... vn = g v1 ... vn. |
|
1372 * |
|
1373 * This prevents name problems in extraction, and helps the result to read |
|
1374 * better. There is a problem with varstructs, since they can introduce more |
|
1375 * than n variables, and some extra reasoning needs to be done. |
|
1376 *---------------------------------------------------------------------------*) |
|
1377 |
|
1378 fun get ([],_,L) = rev L |
|
1379 | get (ant::rst,n,L) = |
|
1380 case (list_break_all ant) |
|
1381 of ([],_) => get (rst, n+1,L) |
|
1382 | (vlist,body) => |
|
1383 let val eq = Logic.strip_imp_concl body |
|
1384 val (f,args) = USyntax.strip_comb (get_lhs eq) |
|
1385 val (vstrl,_) = USyntax.strip_abs f |
|
1386 val names = |
|
1387 Name.variant_list (Misc_Legacy.add_term_names(body, [])) (map (#1 o dest_Free) vstrl) |
|
1388 in get (rst, n+1, (names,n)::L) end |
|
1389 handle TERM _ => get (rst, n+1, L) |
|
1390 | Utils.ERR _ => get (rst, n+1, L); |
|
1391 |
|
1392 (* Note: Thm.rename_params_rule counts from 1, not 0 *) |
|
1393 fun rename thm = |
|
1394 let |
|
1395 val ants = Logic.strip_imp_prems (Thm.prop_of thm) |
|
1396 val news = get (ants,1,[]) |
|
1397 in fold Thm.rename_params_rule news thm end; |
|
1398 |
|
1399 |
|
1400 (*--------------------------------------------------------------------------- |
|
1401 * Beta-conversion to the rhs of an equation (taken from hol90/drule.sml) |
|
1402 *---------------------------------------------------------------------------*) |
|
1403 |
|
1404 fun list_beta_conv tm = |
|
1405 let fun rbeta th = Thm.transitive th (Thm.beta_conversion false (#2(Dcterm.dest_eq(cconcl th)))) |
|
1406 fun iter [] = Thm.reflexive tm |
|
1407 | iter (v::rst) = rbeta (Thm.combination(iter rst) (Thm.reflexive v)) |
|
1408 in iter end; |
|
1409 |
|
1410 |
|
1411 (*--------------------------------------------------------------------------- |
|
1412 * Trace information for the rewriter |
|
1413 *---------------------------------------------------------------------------*) |
|
1414 val tracing = Unsynchronized.ref false; |
|
1415 |
|
1416 fun say s = if !tracing then writeln s else (); |
|
1417 |
|
1418 fun print_thms ctxt s L = |
|
1419 say (cat_lines (s :: map (Display.string_of_thm ctxt) L)); |
|
1420 |
|
1421 fun print_term ctxt s t = |
|
1422 say (cat_lines [s, Syntax.string_of_term ctxt t]); |
|
1423 |
|
1424 |
|
1425 (*--------------------------------------------------------------------------- |
|
1426 * General abstraction handlers, should probably go in USyntax. |
|
1427 *---------------------------------------------------------------------------*) |
|
1428 fun mk_aabs (vstr, body) = |
|
1429 USyntax.mk_abs {Bvar = vstr, Body = body} |
|
1430 handle Utils.ERR _ => USyntax.mk_pabs {varstruct = vstr, body = body}; |
|
1431 |
|
1432 fun list_mk_aabs (vstrl,tm) = |
|
1433 fold_rev (fn vstr => fn tm => mk_aabs(vstr,tm)) vstrl tm; |
|
1434 |
|
1435 fun dest_aabs used tm = |
|
1436 let val ({Bvar,Body}, used') = USyntax.dest_abs used tm |
|
1437 in (Bvar, Body, used') end |
|
1438 handle Utils.ERR _ => |
|
1439 let val {varstruct, body, used} = USyntax.dest_pabs used tm |
|
1440 in (varstruct, body, used) end; |
|
1441 |
|
1442 fun strip_aabs used tm = |
|
1443 let val (vstr, body, used') = dest_aabs used tm |
|
1444 val (bvs, core, used'') = strip_aabs used' body |
|
1445 in (vstr::bvs, core, used'') end |
|
1446 handle Utils.ERR _ => ([], tm, used); |
|
1447 |
|
1448 fun dest_combn tm 0 = (tm,[]) |
|
1449 | dest_combn tm n = |
|
1450 let val {Rator,Rand} = USyntax.dest_comb tm |
|
1451 val (f,rands) = dest_combn Rator (n-1) |
|
1452 in (f,Rand::rands) |
|
1453 end; |
|
1454 |
|
1455 |
|
1456 |
|
1457 |
|
1458 local fun dest_pair M = let val {fst,snd} = USyntax.dest_pair M in (fst,snd) end |
|
1459 fun mk_fst tm = |
|
1460 let val ty as Type(@{type_name Product_Type.prod}, [fty,sty]) = type_of tm |
|
1461 in Const (@{const_name Product_Type.fst}, ty --> fty) $ tm end |
|
1462 fun mk_snd tm = |
|
1463 let val ty as Type(@{type_name Product_Type.prod}, [fty,sty]) = type_of tm |
|
1464 in Const (@{const_name Product_Type.snd}, ty --> sty) $ tm end |
|
1465 in |
|
1466 fun XFILL tych x vstruct = |
|
1467 let fun traverse p xocc L = |
|
1468 if (is_Free p) |
|
1469 then tych xocc::L |
|
1470 else let val (p1,p2) = dest_pair p |
|
1471 in traverse p1 (mk_fst xocc) (traverse p2 (mk_snd xocc) L) |
|
1472 end |
|
1473 in |
|
1474 traverse vstruct x [] |
|
1475 end end; |
|
1476 |
|
1477 (*--------------------------------------------------------------------------- |
|
1478 * Replace a free tuple (vstr) by a universally quantified variable (a). |
|
1479 * Note that the notion of "freeness" for a tuple is different than for a |
|
1480 * variable: if variables in the tuple also occur in any other place than |
|
1481 * an occurrences of the tuple, they aren't "free" (which is thus probably |
|
1482 * the wrong word to use). |
|
1483 *---------------------------------------------------------------------------*) |
|
1484 |
|
1485 fun VSTRUCT_ELIM ctxt tych a vstr th = |
|
1486 let val L = USyntax.free_vars_lr vstr |
|
1487 val bind1 = tych (HOLogic.mk_Trueprop (HOLogic.mk_eq(a,vstr))) |
|
1488 val thm1 = Thm.implies_intr bind1 (SUBS ctxt [SYM(Thm.assume bind1)] th) |
|
1489 val thm2 = forall_intr_list (map tych L) thm1 |
|
1490 val thm3 = forall_elim_list (XFILL tych a vstr) thm2 |
|
1491 in refl RS |
|
1492 rewrite_rule ctxt [Thm.symmetric (@{thm surjective_pairing} RS eq_reflection)] thm3 |
|
1493 end; |
|
1494 |
|
1495 fun PGEN ctxt tych a vstr th = |
|
1496 let val a1 = tych a |
|
1497 val vstr1 = tych vstr |
|
1498 in |
|
1499 Thm.forall_intr a1 |
|
1500 (if (is_Free vstr) |
|
1501 then cterm_instantiate [(vstr1,a1)] th |
|
1502 else VSTRUCT_ELIM ctxt tych a vstr th) |
|
1503 end; |
|
1504 |
|
1505 |
|
1506 (*--------------------------------------------------------------------------- |
|
1507 * Takes apart a paired beta-redex, looking like "(\(x,y).N) vstr", into |
|
1508 * |
|
1509 * (([x,y],N),vstr) |
|
1510 *---------------------------------------------------------------------------*) |
|
1511 fun dest_pbeta_redex used M n = |
|
1512 let val (f,args) = dest_combn M n |
|
1513 val dummy = dest_aabs used f |
|
1514 in (strip_aabs used f,args) |
|
1515 end; |
|
1516 |
|
1517 fun pbeta_redex M n = can (fn t => dest_pbeta_redex [] t n) M; |
|
1518 |
|
1519 fun dest_impl tm = |
|
1520 let val ants = Logic.strip_imp_prems tm |
|
1521 val eq = Logic.strip_imp_concl tm |
|
1522 in (ants,get_lhs eq) |
|
1523 end; |
|
1524 |
|
1525 fun restricted t = is_some (USyntax.find_term |
|
1526 (fn (Const(@{const_name Wfrec.cut},_)) =>true | _ => false) |
|
1527 t) |
|
1528 |
|
1529 fun CONTEXT_REWRITE_RULE main_ctxt (func, G, cut_lemma, congs) th = |
|
1530 let val globals = func::G |
|
1531 val ctxt0 = empty_simpset main_ctxt |
|
1532 val pbeta_reduce = simpl_conv ctxt0 [@{thm split_conv} RS eq_reflection]; |
|
1533 val tc_list = Unsynchronized.ref []: term list Unsynchronized.ref |
|
1534 val cut_lemma' = cut_lemma RS eq_reflection |
|
1535 fun prover used ctxt thm = |
|
1536 let fun cong_prover ctxt thm = |
|
1537 let val dummy = say "cong_prover:" |
|
1538 val cntxt = Simplifier.prems_of ctxt |
|
1539 val dummy = print_thms ctxt "cntxt:" cntxt |
|
1540 val dummy = say "cong rule:" |
|
1541 val dummy = say (Display.string_of_thm ctxt thm) |
|
1542 (* Unquantified eliminate *) |
|
1543 fun uq_eliminate (thm,imp) = |
|
1544 let val tych = Thm.cterm_of ctxt |
|
1545 val _ = print_term ctxt "To eliminate:" imp |
|
1546 val ants = map tych (Logic.strip_imp_prems imp) |
|
1547 val eq = Logic.strip_imp_concl imp |
|
1548 val lhs = tych(get_lhs eq) |
|
1549 val ctxt' = Simplifier.add_prems (map ASSUME ants) ctxt |
|
1550 val lhs_eq_lhs1 = Raw_Simplifier.rewrite_cterm (false,true,false) (prover used) ctxt' lhs |
|
1551 handle Utils.ERR _ => Thm.reflexive lhs |
|
1552 val _ = print_thms ctxt' "proven:" [lhs_eq_lhs1] |
|
1553 val lhs_eq_lhs2 = implies_intr_list ants lhs_eq_lhs1 |
|
1554 val lhs_eeq_lhs2 = lhs_eq_lhs2 RS meta_eq_to_obj_eq |
|
1555 in |
|
1556 lhs_eeq_lhs2 COMP thm |
|
1557 end |
|
1558 fun pq_eliminate (thm, vlist, imp_body, lhs_eq) = |
|
1559 let val ((vstrl, _, used'), args) = dest_pbeta_redex used lhs_eq (length vlist) |
|
1560 val dummy = forall (op aconv) (ListPair.zip (vlist, args)) |
|
1561 orelse error "assertion failed in CONTEXT_REWRITE_RULE" |
|
1562 val imp_body1 = subst_free (ListPair.zip (args, vstrl)) |
|
1563 imp_body |
|
1564 val tych = Thm.cterm_of ctxt |
|
1565 val ants1 = map tych (Logic.strip_imp_prems imp_body1) |
|
1566 val eq1 = Logic.strip_imp_concl imp_body1 |
|
1567 val Q = get_lhs eq1 |
|
1568 val QeqQ1 = pbeta_reduce (tych Q) |
|
1569 val Q1 = #2(Dcterm.dest_eq(cconcl QeqQ1)) |
|
1570 val ctxt' = Simplifier.add_prems (map ASSUME ants1) ctxt |
|
1571 val Q1eeqQ2 = Raw_Simplifier.rewrite_cterm (false,true,false) (prover used') ctxt' Q1 |
|
1572 handle Utils.ERR _ => Thm.reflexive Q1 |
|
1573 val Q2 = #2 (Logic.dest_equals (Thm.prop_of Q1eeqQ2)) |
|
1574 val Q3 = tych(list_comb(list_mk_aabs(vstrl,Q2),vstrl)) |
|
1575 val Q2eeqQ3 = Thm.symmetric(pbeta_reduce Q3 RS eq_reflection) |
|
1576 val thA = Thm.transitive(QeqQ1 RS eq_reflection) Q1eeqQ2 |
|
1577 val QeeqQ3 = Thm.transitive thA Q2eeqQ3 handle THM _ => |
|
1578 ((Q2eeqQ3 RS meta_eq_to_obj_eq) |
|
1579 RS ((thA RS meta_eq_to_obj_eq) RS trans)) |
|
1580 RS eq_reflection |
|
1581 val impth = implies_intr_list ants1 QeeqQ3 |
|
1582 val impth1 = impth RS meta_eq_to_obj_eq |
|
1583 (* Need to abstract *) |
|
1584 val ant_th = Utils.itlist2 (PGEN ctxt' tych) args vstrl impth1 |
|
1585 in ant_th COMP thm |
|
1586 end |
|
1587 fun q_eliminate (thm, imp) = |
|
1588 let val (vlist, imp_body, used') = strip_all used imp |
|
1589 val (ants,Q) = dest_impl imp_body |
|
1590 in if (pbeta_redex Q) (length vlist) |
|
1591 then pq_eliminate (thm, vlist, imp_body, Q) |
|
1592 else |
|
1593 let val tych = Thm.cterm_of ctxt |
|
1594 val ants1 = map tych ants |
|
1595 val ctxt' = Simplifier.add_prems (map ASSUME ants1) ctxt |
|
1596 val Q_eeq_Q1 = Raw_Simplifier.rewrite_cterm |
|
1597 (false,true,false) (prover used') ctxt' (tych Q) |
|
1598 handle Utils.ERR _ => Thm.reflexive (tych Q) |
|
1599 val lhs_eeq_lhs2 = implies_intr_list ants1 Q_eeq_Q1 |
|
1600 val lhs_eq_lhs2 = lhs_eeq_lhs2 RS meta_eq_to_obj_eq |
|
1601 val ant_th = forall_intr_list(map tych vlist)lhs_eq_lhs2 |
|
1602 in |
|
1603 ant_th COMP thm |
|
1604 end end |
|
1605 |
|
1606 fun eliminate thm = |
|
1607 case Thm.prop_of thm of |
|
1608 Const(@{const_name Pure.imp},_) $ imp $ _ => |
|
1609 eliminate |
|
1610 (if not(is_all imp) |
|
1611 then uq_eliminate (thm, imp) |
|
1612 else q_eliminate (thm, imp)) |
|
1613 (* Assume that the leading constant is ==, *) |
|
1614 | _ => thm (* if it is not a ==> *) |
|
1615 in SOME(eliminate (rename thm)) end |
|
1616 handle Utils.ERR _ => NONE (* FIXME handle THM as well?? *) |
|
1617 |
|
1618 fun restrict_prover ctxt thm = |
|
1619 let val _ = say "restrict_prover:" |
|
1620 val cntxt = rev (Simplifier.prems_of ctxt) |
|
1621 val _ = print_thms ctxt "cntxt:" cntxt |
|
1622 val Const(@{const_name Pure.imp},_) $ (Const(@{const_name Trueprop},_) $ A) $ _ = |
|
1623 Thm.prop_of thm |
|
1624 fun genl tm = let val vlist = subtract (op aconv) globals |
|
1625 (Misc_Legacy.add_term_frees(tm,[])) |
|
1626 in fold_rev Forall vlist tm |
|
1627 end |
|
1628 (*-------------------------------------------------------------- |
|
1629 * This actually isn't quite right, since it will think that |
|
1630 * not-fully applied occs. of "f" in the context mean that the |
|
1631 * current call is nested. The real solution is to pass in a |
|
1632 * term "f v1..vn" which is a pattern that any full application |
|
1633 * of "f" will match. |
|
1634 *-------------------------------------------------------------*) |
|
1635 val func_name = #1(dest_Const func) |
|
1636 fun is_func (Const (name,_)) = (name = func_name) |
|
1637 | is_func _ = false |
|
1638 val rcontext = rev cntxt |
|
1639 val cncl = HOLogic.dest_Trueprop o Thm.prop_of |
|
1640 val antl = case rcontext of [] => [] |
|
1641 | _ => [USyntax.list_mk_conj(map cncl rcontext)] |
|
1642 val TC = genl(USyntax.list_mk_imp(antl, A)) |
|
1643 val _ = print_term ctxt "func:" func |
|
1644 val _ = print_term ctxt "TC:" (HOLogic.mk_Trueprop TC) |
|
1645 val _ = tc_list := (TC :: !tc_list) |
|
1646 val nestedp = is_some (USyntax.find_term is_func TC) |
|
1647 val _ = if nestedp then say "nested" else say "not_nested" |
|
1648 val th' = if nestedp then raise RULES_ERR "solver" "nested function" |
|
1649 else let val cTC = Thm.cterm_of ctxt (HOLogic.mk_Trueprop TC) |
|
1650 in case rcontext of |
|
1651 [] => SPEC_ALL(ASSUME cTC) |
|
1652 | _ => MP (SPEC_ALL (ASSUME cTC)) |
|
1653 (LIST_CONJ rcontext) |
|
1654 end |
|
1655 val th'' = th' RS thm |
|
1656 in SOME (th'') |
|
1657 end handle Utils.ERR _ => NONE (* FIXME handle THM as well?? *) |
|
1658 in |
|
1659 (if (is_cong thm) then cong_prover else restrict_prover) ctxt thm |
|
1660 end |
|
1661 val ctm = Thm.cprop_of th |
|
1662 val names = Misc_Legacy.add_term_names (Thm.term_of ctm, []) |
|
1663 val th1 = |
|
1664 Raw_Simplifier.rewrite_cterm (false, true, false) |
|
1665 (prover names) (ctxt0 addsimps [cut_lemma'] |> fold Simplifier.add_eqcong congs) ctm |
|
1666 val th2 = Thm.equal_elim th1 th |
|
1667 in |
|
1668 (th2, filter_out restricted (!tc_list)) |
|
1669 end; |
|
1670 |
|
1671 |
|
1672 fun prove ctxt strict (t, tac) = |
|
1673 let |
|
1674 val ctxt' = Variable.auto_fixes t ctxt; |
|
1675 in |
|
1676 if strict |
|
1677 then Goal.prove ctxt' [] [] t (K tac) |
|
1678 else Goal.prove ctxt' [] [] t (K tac) |
|
1679 handle ERROR msg => (warning msg; raise RULES_ERR "prove" msg) |
|
1680 end; |
|
1681 |
|
1682 end; |
|
1683 |
|
1684 |
|
1685 (*** theory operations ***) |
|
1686 |
|
1687 structure Thry: THRY = |
|
1688 struct |
|
1689 |
|
1690 |
|
1691 fun THRY_ERR func mesg = Utils.ERR {module = "Thry", func = func, mesg = mesg}; |
|
1692 |
|
1693 |
|
1694 (*--------------------------------------------------------------------------- |
|
1695 * Matching |
|
1696 *---------------------------------------------------------------------------*) |
|
1697 |
|
1698 local |
|
1699 |
|
1700 fun tybind (ixn, (S, T)) = (TVar (ixn, S), T); |
|
1701 |
|
1702 in |
|
1703 |
|
1704 fun match_term thry pat ob = |
|
1705 let |
|
1706 val (ty_theta, tm_theta) = Pattern.match thry (pat,ob) (Vartab.empty, Vartab.empty); |
|
1707 fun tmbind (ixn, (T, t)) = (Var (ixn, Envir.subst_type ty_theta T), t) |
|
1708 in (map tmbind (Vartab.dest tm_theta), map tybind (Vartab.dest ty_theta)) |
|
1709 end; |
|
1710 |
|
1711 fun match_type thry pat ob = |
|
1712 map tybind (Vartab.dest (Sign.typ_match thry (pat, ob) Vartab.empty)); |
|
1713 |
|
1714 end; |
|
1715 |
|
1716 |
|
1717 (*--------------------------------------------------------------------------- |
|
1718 * Typing |
|
1719 *---------------------------------------------------------------------------*) |
|
1720 |
|
1721 fun typecheck thy t = |
|
1722 Thm.global_cterm_of thy t |
|
1723 handle TYPE (msg, _, _) => raise THRY_ERR "typecheck" msg |
|
1724 | TERM (msg, _) => raise THRY_ERR "typecheck" msg; |
|
1725 |
|
1726 |
|
1727 (*--------------------------------------------------------------------------- |
|
1728 * Get information about datatypes |
|
1729 *---------------------------------------------------------------------------*) |
|
1730 |
|
1731 fun match_info thy dtco = |
|
1732 case (BNF_LFP_Compat.get_info thy [BNF_LFP_Compat.Keep_Nesting] dtco, |
|
1733 BNF_LFP_Compat.get_constrs thy dtco) of |
|
1734 (SOME {case_name, ... }, SOME constructors) => |
|
1735 SOME {case_const = Const (case_name, Sign.the_const_type thy case_name), constructors = map Const constructors} |
|
1736 | _ => NONE; |
|
1737 |
|
1738 fun induct_info thy dtco = case BNF_LFP_Compat.get_info thy [BNF_LFP_Compat.Keep_Nesting] dtco of |
|
1739 NONE => NONE |
|
1740 | SOME {nchotomy, ...} => |
|
1741 SOME {nchotomy = nchotomy, |
|
1742 constructors = (map Const o the o BNF_LFP_Compat.get_constrs thy) dtco}; |
|
1743 |
|
1744 fun extract_info thy = |
|
1745 let val infos = map snd (Symtab.dest (BNF_LFP_Compat.get_all thy [BNF_LFP_Compat.Keep_Nesting])) |
|
1746 in {case_congs = map (mk_meta_eq o #case_cong) infos, |
|
1747 case_rewrites = maps (map mk_meta_eq o #case_rewrites) infos} |
|
1748 end; |
|
1749 |
|
1750 |
|
1751 end; |
|
1752 |
|
1753 |
|
1754 (*** first part of main module ***) |
|
1755 |
|
1756 structure Prim: PRIM = |
|
1757 struct |
|
1758 |
|
1759 val trace = Unsynchronized.ref false; |
|
1760 |
|
1761 |
|
1762 fun TFL_ERR func mesg = Utils.ERR {module = "Tfl", func = func, mesg = mesg}; |
|
1763 |
|
1764 val concl = #2 o Rules.dest_thm; |
|
1765 val hyp = #1 o Rules.dest_thm; |
|
1766 |
|
1767 val list_mk_type = Utils.end_itlist (curry (op -->)); |
|
1768 |
|
1769 fun front_last [] = raise TFL_ERR "front_last" "empty list" |
|
1770 | front_last [x] = ([],x) |
|
1771 | front_last (h::t) = |
|
1772 let val (pref,x) = front_last t |
|
1773 in |
|
1774 (h::pref,x) |
|
1775 end; |
|
1776 |
|
1777 |
|
1778 (*--------------------------------------------------------------------------- |
|
1779 * The next function is common to pattern-match translation and |
|
1780 * proof of completeness of cases for the induction theorem. |
|
1781 * |
|
1782 * The curried function "gvvariant" returns a function to generate distinct |
|
1783 * variables that are guaranteed not to be in names. The names of |
|
1784 * the variables go u, v, ..., z, aa, ..., az, ... The returned |
|
1785 * function contains embedded refs! |
|
1786 *---------------------------------------------------------------------------*) |
|
1787 fun gvvariant names = |
|
1788 let val slist = Unsynchronized.ref names |
|
1789 val vname = Unsynchronized.ref "u" |
|
1790 fun new() = |
|
1791 if member (op =) (!slist) (!vname) |
|
1792 then (vname := Symbol.bump_string (!vname); new()) |
|
1793 else (slist := !vname :: !slist; !vname) |
|
1794 in |
|
1795 fn ty => Free(new(), ty) |
|
1796 end; |
|
1797 |
|
1798 |
|
1799 (*--------------------------------------------------------------------------- |
|
1800 * Used in induction theorem production. This is the simple case of |
|
1801 * partitioning up pattern rows by the leading constructor. |
|
1802 *---------------------------------------------------------------------------*) |
|
1803 fun ipartition gv (constructors,rows) = |
|
1804 let fun pfail s = raise TFL_ERR "partition.part" s |
|
1805 fun part {constrs = [], rows = [], A} = rev A |
|
1806 | part {constrs = [], rows = _::_, A} = pfail"extra cases in defn" |
|
1807 | part {constrs = _::_, rows = [], A} = pfail"cases missing in defn" |
|
1808 | part {constrs = c::crst, rows, A} = |
|
1809 let val (c, T) = dest_Const c |
|
1810 val L = binder_types T |
|
1811 val (in_group, not_in_group) = |
|
1812 fold_rev (fn (row as (p::rst, rhs)) => |
|
1813 fn (in_group,not_in_group) => |
|
1814 let val (pc,args) = USyntax.strip_comb p |
|
1815 in if (#1(dest_Const pc) = c) |
|
1816 then ((args@rst, rhs)::in_group, not_in_group) |
|
1817 else (in_group, row::not_in_group) |
|
1818 end) rows ([],[]) |
|
1819 val col_types = Utils.take type_of (length L, #1(hd in_group)) |
|
1820 in |
|
1821 part{constrs = crst, rows = not_in_group, |
|
1822 A = {constructor = c, |
|
1823 new_formals = map gv col_types, |
|
1824 group = in_group}::A} |
|
1825 end |
|
1826 in part{constrs = constructors, rows = rows, A = []} |
|
1827 end; |
|
1828 |
|
1829 |
|
1830 |
|
1831 (*--------------------------------------------------------------------------- |
|
1832 * Each pattern carries with it a tag (i,b) where |
|
1833 * i is the clause it came from and |
|
1834 * b=true indicates that clause was given by the user |
|
1835 * (or is an instantiation of a user supplied pattern) |
|
1836 * b=false --> i = ~1 |
|
1837 *---------------------------------------------------------------------------*) |
|
1838 |
|
1839 type pattern = term * (int * bool) |
|
1840 |
|
1841 fun pattern_map f (tm,x) = (f tm, x); |
|
1842 |
|
1843 fun pattern_subst theta = pattern_map (subst_free theta); |
|
1844 |
|
1845 val pat_of = fst; |
|
1846 fun row_of_pat x = fst (snd x); |
|
1847 fun given x = snd (snd x); |
|
1848 |
|
1849 (*--------------------------------------------------------------------------- |
|
1850 * Produce an instance of a constructor, plus genvars for its arguments. |
|
1851 *---------------------------------------------------------------------------*) |
|
1852 fun fresh_constr ty_match colty gv c = |
|
1853 let val (_,Ty) = dest_Const c |
|
1854 val L = binder_types Ty |
|
1855 and ty = body_type Ty |
|
1856 val ty_theta = ty_match ty colty |
|
1857 val c' = USyntax.inst ty_theta c |
|
1858 val gvars = map (USyntax.inst ty_theta o gv) L |
|
1859 in (c', gvars) |
|
1860 end; |
|
1861 |
|
1862 |
|
1863 (*--------------------------------------------------------------------------- |
|
1864 * Goes through a list of rows and picks out the ones beginning with a |
|
1865 * pattern with constructor = name. |
|
1866 *---------------------------------------------------------------------------*) |
|
1867 fun mk_group name rows = |
|
1868 fold_rev (fn (row as ((prfx, p::rst), rhs)) => |
|
1869 fn (in_group,not_in_group) => |
|
1870 let val (pc,args) = USyntax.strip_comb p |
|
1871 in if ((#1 (Term.dest_Const pc) = name) handle TERM _ => false) |
|
1872 then (((prfx,args@rst), rhs)::in_group, not_in_group) |
|
1873 else (in_group, row::not_in_group) end) |
|
1874 rows ([],[]); |
|
1875 |
|
1876 (*--------------------------------------------------------------------------- |
|
1877 * Partition the rows. Not efficient: we should use hashing. |
|
1878 *---------------------------------------------------------------------------*) |
|
1879 fun partition _ _ (_,_,_,[]) = raise TFL_ERR "partition" "no rows" |
|
1880 | partition gv ty_match |
|
1881 (constructors, colty, res_ty, rows as (((prfx,_),_)::_)) = |
|
1882 let val fresh = fresh_constr ty_match colty gv |
|
1883 fun part {constrs = [], rows, A} = rev A |
|
1884 | part {constrs = c::crst, rows, A} = |
|
1885 let val (c',gvars) = fresh c |
|
1886 val (in_group, not_in_group) = mk_group (#1 (dest_Const c')) rows |
|
1887 val in_group' = |
|
1888 if (null in_group) (* Constructor not given *) |
|
1889 then [((prfx, #2(fresh c)), (USyntax.ARB res_ty, (~1,false)))] |
|
1890 else in_group |
|
1891 in |
|
1892 part{constrs = crst, |
|
1893 rows = not_in_group, |
|
1894 A = {constructor = c', |
|
1895 new_formals = gvars, |
|
1896 group = in_group'}::A} |
|
1897 end |
|
1898 in part{constrs=constructors, rows=rows, A=[]} |
|
1899 end; |
|
1900 |
|
1901 (*--------------------------------------------------------------------------- |
|
1902 * Misc. routines used in mk_case |
|
1903 *---------------------------------------------------------------------------*) |
|
1904 |
|
1905 fun mk_pat (c,l) = |
|
1906 let val L = length (binder_types (type_of c)) |
|
1907 fun build (prfx,tag,plist) = |
|
1908 let val (args, plist') = chop L plist |
|
1909 in (prfx,tag,list_comb(c,args)::plist') end |
|
1910 in map build l end; |
|
1911 |
|
1912 fun v_to_prfx (prfx, v::pats) = (v::prfx,pats) |
|
1913 | v_to_prfx _ = raise TFL_ERR "mk_case" "v_to_prfx"; |
|
1914 |
|
1915 fun v_to_pats (v::prfx,tag, pats) = (prfx, tag, v::pats) |
|
1916 | v_to_pats _ = raise TFL_ERR "mk_case" "v_to_pats"; |
|
1917 |
|
1918 |
|
1919 (*---------------------------------------------------------------------------- |
|
1920 * Translation of pattern terms into nested case expressions. |
|
1921 * |
|
1922 * This performs the translation and also builds the full set of patterns. |
|
1923 * Thus it supports the construction of induction theorems even when an |
|
1924 * incomplete set of patterns is given. |
|
1925 *---------------------------------------------------------------------------*) |
|
1926 |
|
1927 fun mk_case ty_info ty_match usednames range_ty = |
|
1928 let |
|
1929 fun mk_case_fail s = raise TFL_ERR "mk_case" s |
|
1930 val fresh_var = gvvariant usednames |
|
1931 val divide = partition fresh_var ty_match |
|
1932 fun expand constructors ty ((_,[]), _) = mk_case_fail"expand_var_row" |
|
1933 | expand constructors ty (row as ((prfx, p::rst), rhs)) = |
|
1934 if (is_Free p) |
|
1935 then let val fresh = fresh_constr ty_match ty fresh_var |
|
1936 fun expnd (c,gvs) = |
|
1937 let val capp = list_comb(c,gvs) |
|
1938 in ((prfx, capp::rst), pattern_subst[(p,capp)] rhs) |
|
1939 end |
|
1940 in map expnd (map fresh constructors) end |
|
1941 else [row] |
|
1942 fun mk{rows=[],...} = mk_case_fail"no rows" |
|
1943 | mk{path=[], rows = ((prfx, []), (tm,tag))::_} = (* Done *) |
|
1944 ([(prfx,tag,[])], tm) |
|
1945 | mk{path=[], rows = _::_} = mk_case_fail"blunder" |
|
1946 | mk{path as u::rstp, rows as ((prfx, []), rhs)::rst} = |
|
1947 mk{path = path, |
|
1948 rows = ((prfx, [fresh_var(type_of u)]), rhs)::rst} |
|
1949 | mk{path = u::rstp, rows as ((_, p::_), _)::_} = |
|
1950 let val (pat_rectangle,rights) = ListPair.unzip rows |
|
1951 val col0 = map(hd o #2) pat_rectangle |
|
1952 in |
|
1953 if (forall is_Free col0) |
|
1954 then let val rights' = map (fn(v,e) => pattern_subst[(v,u)] e) |
|
1955 (ListPair.zip (col0, rights)) |
|
1956 val pat_rectangle' = map v_to_prfx pat_rectangle |
|
1957 val (pref_patl,tm) = mk{path = rstp, |
|
1958 rows = ListPair.zip (pat_rectangle', |
|
1959 rights')} |
|
1960 in (map v_to_pats pref_patl, tm) |
|
1961 end |
|
1962 else |
|
1963 let val pty as Type (ty_name,_) = type_of p |
|
1964 in |
|
1965 case (ty_info ty_name) |
|
1966 of NONE => mk_case_fail("Not a known datatype: "^ty_name) |
|
1967 | SOME{case_const,constructors} => |
|
1968 let |
|
1969 val case_const_name = #1(dest_Const case_const) |
|
1970 val nrows = maps (expand constructors pty) rows |
|
1971 val subproblems = divide(constructors, pty, range_ty, nrows) |
|
1972 val groups = map #group subproblems |
|
1973 and new_formals = map #new_formals subproblems |
|
1974 and constructors' = map #constructor subproblems |
|
1975 val news = map (fn (nf,rows) => {path = nf@rstp, rows=rows}) |
|
1976 (ListPair.zip (new_formals, groups)) |
|
1977 val rec_calls = map mk news |
|
1978 val (pat_rect,dtrees) = ListPair.unzip rec_calls |
|
1979 val case_functions = map USyntax.list_mk_abs |
|
1980 (ListPair.zip (new_formals, dtrees)) |
|
1981 val types = map type_of (case_functions@[u]) @ [range_ty] |
|
1982 val case_const' = Const(case_const_name, list_mk_type types) |
|
1983 val tree = list_comb(case_const', case_functions@[u]) |
|
1984 val pat_rect1 = flat (ListPair.map mk_pat (constructors', pat_rect)) |
|
1985 in (pat_rect1,tree) |
|
1986 end |
|
1987 end end |
|
1988 in mk |
|
1989 end; |
|
1990 |
|
1991 |
|
1992 (* Repeated variable occurrences in a pattern are not allowed. *) |
|
1993 fun FV_multiset tm = |
|
1994 case (USyntax.dest_term tm) |
|
1995 of USyntax.VAR{Name = c, Ty = T} => [Free(c, T)] |
|
1996 | USyntax.CONST _ => [] |
|
1997 | USyntax.COMB{Rator, Rand} => FV_multiset Rator @ FV_multiset Rand |
|
1998 | USyntax.LAMB _ => raise TFL_ERR "FV_multiset" "lambda"; |
|
1999 |
|
2000 fun no_repeat_vars thy pat = |
|
2001 let fun check [] = true |
|
2002 | check (v::rst) = |
|
2003 if member (op aconv) rst v then |
|
2004 raise TFL_ERR "no_repeat_vars" |
|
2005 (quote (#1 (dest_Free v)) ^ |
|
2006 " occurs repeatedly in the pattern " ^ |
|
2007 quote (Syntax.string_of_term_global thy pat)) |
|
2008 else check rst |
|
2009 in check (FV_multiset pat) |
|
2010 end; |
|
2011 |
|
2012 fun dest_atom (Free p) = p |
|
2013 | dest_atom (Const p) = p |
|
2014 | dest_atom _ = raise TFL_ERR "dest_atom" "function name not an identifier"; |
|
2015 |
|
2016 fun same_name (p,q) = #1(dest_atom p) = #1(dest_atom q); |
|
2017 |
|
2018 local fun mk_functional_err s = raise TFL_ERR "mk_functional" s |
|
2019 fun single [_$_] = |
|
2020 mk_functional_err "recdef does not allow currying" |
|
2021 | single [f] = f |
|
2022 | single fs = |
|
2023 (*multiple function names?*) |
|
2024 if length (distinct same_name fs) < length fs |
|
2025 then mk_functional_err |
|
2026 "The function being declared appears with multiple types" |
|
2027 else mk_functional_err |
|
2028 (string_of_int (length fs) ^ |
|
2029 " distinct function names being declared") |
|
2030 in |
|
2031 fun mk_functional thy clauses = |
|
2032 let val (L,R) = ListPair.unzip (map HOLogic.dest_eq clauses |
|
2033 handle TERM _ => raise TFL_ERR "mk_functional" |
|
2034 "recursion equations must use the = relation") |
|
2035 val (funcs,pats) = ListPair.unzip (map (fn (t$u) =>(t,u)) L) |
|
2036 val atom = single (distinct (op aconv) funcs) |
|
2037 val (fname,ftype) = dest_atom atom |
|
2038 val dummy = map (no_repeat_vars thy) pats |
|
2039 val rows = ListPair.zip (map (fn x => ([]:term list,[x])) pats, |
|
2040 map_index (fn (i, t) => (t,(i,true))) R) |
|
2041 val names = List.foldr Misc_Legacy.add_term_names [] R |
|
2042 val atype = type_of(hd pats) |
|
2043 and aname = singleton (Name.variant_list names) "a" |
|
2044 val a = Free(aname,atype) |
|
2045 val ty_info = Thry.match_info thy |
|
2046 val ty_match = Thry.match_type thy |
|
2047 val range_ty = type_of (hd R) |
|
2048 val (patts, case_tm) = mk_case ty_info ty_match (aname::names) range_ty |
|
2049 {path=[a], rows=rows} |
|
2050 val patts1 = map (fn (_,tag,[pat]) => (pat,tag)) patts |
|
2051 handle Match => mk_functional_err "error in pattern-match translation" |
|
2052 val patts2 = Library.sort (Library.int_ord o apply2 row_of_pat) patts1 |
|
2053 val finals = map row_of_pat patts2 |
|
2054 val originals = map (row_of_pat o #2) rows |
|
2055 val dummy = case (subtract (op =) finals originals) |
|
2056 of [] => () |
|
2057 | L => mk_functional_err |
|
2058 ("The following clauses are redundant (covered by preceding clauses): " ^ |
|
2059 commas (map (fn i => string_of_int (i + 1)) L)) |
|
2060 in {functional = Abs(Long_Name.base_name fname, ftype, |
|
2061 abstract_over (atom, absfree (aname,atype) case_tm)), |
|
2062 pats = patts2} |
|
2063 end end; |
|
2064 |
|
2065 |
|
2066 (*---------------------------------------------------------------------------- |
|
2067 * |
|
2068 * PRINCIPLES OF DEFINITION |
|
2069 * |
|
2070 *---------------------------------------------------------------------------*) |
|
2071 |
|
2072 |
|
2073 (*For Isabelle, the lhs of a definition must be a constant.*) |
|
2074 fun const_def sign (c, Ty, rhs) = |
|
2075 singleton (Syntax.check_terms (Proof_Context.init_global sign)) |
|
2076 (Const(@{const_name Pure.eq},dummyT) $ Const(c,Ty) $ rhs); |
|
2077 |
|
2078 (*Make all TVars available for instantiation by adding a ? to the front*) |
|
2079 fun poly_tvars (Type(a,Ts)) = Type(a, map (poly_tvars) Ts) |
|
2080 | poly_tvars (TFree (a,sort)) = TVar (("?" ^ a, 0), sort) |
|
2081 | poly_tvars (TVar ((a,i),sort)) = TVar (("?" ^ a, i+1), sort); |
|
2082 |
|
2083 local |
|
2084 val f_eq_wfrec_R_M = |
|
2085 #ant(USyntax.dest_imp(#2(USyntax.strip_forall (concl Thms.WFREC_COROLLARY)))) |
|
2086 val {lhs=f, rhs} = USyntax.dest_eq f_eq_wfrec_R_M |
|
2087 val (fname,_) = dest_Free f |
|
2088 val (wfrec,_) = USyntax.strip_comb rhs |
|
2089 in |
|
2090 |
|
2091 fun wfrec_definition0 fid R (functional as Abs(x, Ty, _)) thy = |
|
2092 let |
|
2093 val def_name = Thm.def_name (Long_Name.base_name fid) |
|
2094 val wfrec_R_M = map_types poly_tvars (wfrec $ map_types poly_tvars R) $ functional |
|
2095 val def_term = const_def thy (fid, Ty, wfrec_R_M) |
|
2096 val ([def], thy') = |
|
2097 Global_Theory.add_defs false [Thm.no_attributes (Binding.name def_name, def_term)] thy |
|
2098 in (def, thy') end; |
|
2099 |
|
2100 end; |
|
2101 |
|
2102 |
|
2103 |
|
2104 (*--------------------------------------------------------------------------- |
|
2105 * This structure keeps track of congruence rules that aren't derived |
|
2106 * from a datatype definition. |
|
2107 *---------------------------------------------------------------------------*) |
|
2108 fun extraction_thms thy = |
|
2109 let val {case_rewrites,case_congs} = Thry.extract_info thy |
|
2110 in (case_rewrites, case_congs) |
|
2111 end; |
|
2112 |
|
2113 |
|
2114 (*--------------------------------------------------------------------------- |
|
2115 * Pair patterns with termination conditions. The full list of patterns for |
|
2116 * a definition is merged with the TCs arising from the user-given clauses. |
|
2117 * There can be fewer clauses than the full list, if the user omitted some |
|
2118 * cases. This routine is used to prepare input for mk_induction. |
|
2119 *---------------------------------------------------------------------------*) |
|
2120 fun merge full_pats TCs = |
|
2121 let fun insert (p,TCs) = |
|
2122 let fun insrt ((x as (h,[]))::rst) = |
|
2123 if (p aconv h) then (p,TCs)::rst else x::insrt rst |
|
2124 | insrt (x::rst) = x::insrt rst |
|
2125 | insrt[] = raise TFL_ERR "merge.insert" "pattern not found" |
|
2126 in insrt end |
|
2127 fun pass ([],ptcl_final) = ptcl_final |
|
2128 | pass (ptcs::tcl, ptcl) = pass(tcl, insert ptcs ptcl) |
|
2129 in |
|
2130 pass (TCs, map (fn p => (p,[])) full_pats) |
|
2131 end; |
|
2132 |
|
2133 |
|
2134 fun givens pats = map pat_of (filter given pats); |
|
2135 |
|
2136 fun post_definition ctxt meta_tflCongs (def, pats) = |
|
2137 let val thy = Proof_Context.theory_of ctxt |
|
2138 val tych = Thry.typecheck thy |
|
2139 val f = #lhs(USyntax.dest_eq(concl def)) |
|
2140 val corollary = Rules.MATCH_MP Thms.WFREC_COROLLARY def |
|
2141 val pats' = filter given pats |
|
2142 val given_pats = map pat_of pats' |
|
2143 val rows = map row_of_pat pats' |
|
2144 val WFR = #ant(USyntax.dest_imp(concl corollary)) |
|
2145 val R = #Rand(USyntax.dest_comb WFR) |
|
2146 val corollary' = Rules.UNDISCH corollary (* put WF R on assums *) |
|
2147 val corollaries = map (fn pat => Rules.SPEC (tych pat) corollary') given_pats |
|
2148 val (case_rewrites,context_congs) = extraction_thms thy |
|
2149 (*case_ss causes minimal simplification: bodies of case expressions are |
|
2150 not simplified. Otherwise large examples (Red-Black trees) are too |
|
2151 slow.*) |
|
2152 val case_simpset = |
|
2153 put_simpset HOL_basic_ss ctxt |
|
2154 addsimps case_rewrites |
|
2155 |> fold (Simplifier.add_cong o #case_cong_weak o snd) |
|
2156 (Symtab.dest (BNF_LFP_Compat.get_all thy [BNF_LFP_Compat.Keep_Nesting])) |
|
2157 val corollaries' = map (Simplifier.simplify case_simpset) corollaries |
|
2158 val extract = |
|
2159 Rules.CONTEXT_REWRITE_RULE ctxt (f, [R], @{thm cut_apply}, meta_tflCongs @ context_congs) |
|
2160 val (rules, TCs) = ListPair.unzip (map extract corollaries') |
|
2161 val rules0 = map (rewrite_rule ctxt [Thms.CUT_DEF]) rules |
|
2162 val mk_cond_rule = Rules.FILTER_DISCH_ALL(not o curry (op aconv) WFR) |
|
2163 val rules1 = Rules.LIST_CONJ(map mk_cond_rule rules0) |
|
2164 in |
|
2165 {rules = rules1, |
|
2166 rows = rows, |
|
2167 full_pats_TCs = merge (map pat_of pats) (ListPair.zip (given_pats, TCs)), |
|
2168 TCs = TCs} |
|
2169 end; |
|
2170 |
|
2171 |
|
2172 (*--------------------------------------------------------------------------- |
|
2173 * Perform the extraction without making the definition. Definition and |
|
2174 * extraction commute for the non-nested case. (Deferred recdefs) |
|
2175 * |
|
2176 * The purpose of wfrec_eqns is merely to instantiate the recursion theorem |
|
2177 * and extract termination conditions: no definition is made. |
|
2178 *---------------------------------------------------------------------------*) |
|
2179 |
|
2180 fun wfrec_eqns thy fid tflCongs eqns = |
|
2181 let val ctxt = Proof_Context.init_global thy |
|
2182 val {lhs,rhs} = USyntax.dest_eq (hd eqns) |
|
2183 val (f,args) = USyntax.strip_comb lhs |
|
2184 val (fname,fty) = dest_atom f |
|
2185 val (SV,a) = front_last args (* SV = schematic variables *) |
|
2186 val g = list_comb(f,SV) |
|
2187 val h = Free(fname,type_of g) |
|
2188 val eqns1 = map (subst_free[(g,h)]) eqns |
|
2189 val {functional as Abs(x, Ty, _), pats} = mk_functional thy eqns1 |
|
2190 val given_pats = givens pats |
|
2191 (* val f = Free(x,Ty) *) |
|
2192 val Type("fun", [f_dty, f_rty]) = Ty |
|
2193 val dummy = if x<>fid then |
|
2194 raise TFL_ERR "wfrec_eqns" |
|
2195 ("Expected a definition of " ^ |
|
2196 quote fid ^ " but found one of " ^ |
|
2197 quote x) |
|
2198 else () |
|
2199 val (case_rewrites,context_congs) = extraction_thms thy |
|
2200 val tych = Thry.typecheck thy |
|
2201 val WFREC_THM0 = Rules.ISPEC (tych functional) Thms.WFREC_COROLLARY |
|
2202 val Const(@{const_name All},_) $ Abs(Rname,Rtype,_) = concl WFREC_THM0 |
|
2203 val R = Free (singleton (Name.variant_list (List.foldr Misc_Legacy.add_term_names [] eqns)) Rname, |
|
2204 Rtype) |
|
2205 val WFREC_THM = Rules.ISPECL [tych R, tych g] WFREC_THM0 |
|
2206 val ([proto_def, WFR],_) = USyntax.strip_imp(concl WFREC_THM) |
|
2207 val dummy = |
|
2208 if !trace then |
|
2209 writeln ("ORIGINAL PROTO_DEF: " ^ |
|
2210 Syntax.string_of_term_global thy proto_def) |
|
2211 else () |
|
2212 val R1 = USyntax.rand WFR |
|
2213 val corollary' = Rules.UNDISCH (Rules.UNDISCH WFREC_THM) |
|
2214 val corollaries = map (fn pat => Rules.SPEC (tych pat) corollary') given_pats |
|
2215 val corollaries' = map (rewrite_rule ctxt case_rewrites) corollaries |
|
2216 val extract = |
|
2217 Rules.CONTEXT_REWRITE_RULE ctxt (f, R1::SV, @{thm cut_apply}, tflCongs @ context_congs) |
|
2218 in {proto_def = proto_def, |
|
2219 SV=SV, |
|
2220 WFR=WFR, |
|
2221 pats=pats, |
|
2222 extracta = map extract corollaries'} |
|
2223 end; |
|
2224 |
|
2225 |
|
2226 (*--------------------------------------------------------------------------- |
|
2227 * Define the constant after extracting the termination conditions. The |
|
2228 * wellfounded relation used in the definition is computed by using the |
|
2229 * choice operator on the extracted conditions (plus the condition that |
|
2230 * such a relation must be wellfounded). |
|
2231 *---------------------------------------------------------------------------*) |
|
2232 |
|
2233 fun lazyR_def thy fid tflCongs eqns = |
|
2234 let val {proto_def,WFR,pats,extracta,SV} = |
|
2235 wfrec_eqns thy fid tflCongs eqns |
|
2236 val R1 = USyntax.rand WFR |
|
2237 val f = #lhs(USyntax.dest_eq proto_def) |
|
2238 val (extractants,TCl) = ListPair.unzip extracta |
|
2239 val dummy = if !trace |
|
2240 then writeln (cat_lines ("Extractants =" :: |
|
2241 map (Display.string_of_thm_global thy) extractants)) |
|
2242 else () |
|
2243 val TCs = fold_rev (union (op aconv)) TCl [] |
|
2244 val full_rqt = WFR::TCs |
|
2245 val R' = USyntax.mk_select{Bvar=R1, Body=USyntax.list_mk_conj full_rqt} |
|
2246 val R'abs = USyntax.rand R' |
|
2247 val proto_def' = subst_free[(R1,R')] proto_def |
|
2248 val dummy = if !trace then writeln ("proto_def' = " ^ |
|
2249 Syntax.string_of_term_global |
|
2250 thy proto_def') |
|
2251 else () |
|
2252 val {lhs,rhs} = USyntax.dest_eq proto_def' |
|
2253 val (c,args) = USyntax.strip_comb lhs |
|
2254 val (name,Ty) = dest_atom c |
|
2255 val defn = const_def thy (name, Ty, USyntax.list_mk_abs (args,rhs)) |
|
2256 val ([def0], thy') = |
|
2257 thy |
|
2258 |> Global_Theory.add_defs false |
|
2259 [Thm.no_attributes (Binding.name (Thm.def_name fid), defn)] |
|
2260 val def = Thm.unvarify_global def0; |
|
2261 val ctxt' = Syntax.init_pretty_global thy'; |
|
2262 val dummy = |
|
2263 if !trace then writeln ("DEF = " ^ Display.string_of_thm ctxt' def) |
|
2264 else () |
|
2265 (* val fconst = #lhs(USyntax.dest_eq(concl def)) *) |
|
2266 val tych = Thry.typecheck thy' |
|
2267 val full_rqt_prop = map (Dcterm.mk_prop o tych) full_rqt |
|
2268 (*lcp: a lot of object-logic inference to remove*) |
|
2269 val baz = Rules.DISCH_ALL |
|
2270 (fold_rev Rules.DISCH full_rqt_prop |
|
2271 (Rules.LIST_CONJ extractants)) |
|
2272 val dum = if !trace then writeln ("baz = " ^ Display.string_of_thm ctxt' baz) else () |
|
2273 val f_free = Free (fid, fastype_of f) (*'cos f is a Const*) |
|
2274 val SV' = map tych SV; |
|
2275 val SVrefls = map Thm.reflexive SV' |
|
2276 val def0 = (fold (fn x => fn th => Rules.rbeta(Thm.combination th x)) |
|
2277 SVrefls def) |
|
2278 RS meta_eq_to_obj_eq |
|
2279 val def' = Rules.MP (Rules.SPEC (tych R') (Rules.GEN ctxt' (tych R1) baz)) def0 |
|
2280 val body_th = Rules.LIST_CONJ (map Rules.ASSUME full_rqt_prop) |
|
2281 val SELECT_AX = (*in this way we hope to avoid a STATIC dependence upon |
|
2282 theory Hilbert_Choice*) |
|
2283 ML_Context.thm "Hilbert_Choice.tfl_some" |
|
2284 handle ERROR msg => cat_error msg |
|
2285 "defer_recdef requires theory Main or at least Hilbert_Choice as parent" |
|
2286 val bar = Rules.MP (Rules.ISPECL[tych R'abs, tych R1] SELECT_AX) body_th |
|
2287 in {theory = thy', R=R1, SV=SV, |
|
2288 rules = fold (fn a => fn b => Rules.MP b a) (Rules.CONJUNCTS bar) def', |
|
2289 full_pats_TCs = merge (map pat_of pats) (ListPair.zip (givens pats, TCl)), |
|
2290 patterns = pats} |
|
2291 end; |
|
2292 |
|
2293 |
|
2294 |
|
2295 (*---------------------------------------------------------------------------- |
|
2296 * |
|
2297 * INDUCTION THEOREM |
|
2298 * |
|
2299 *---------------------------------------------------------------------------*) |
|
2300 |
|
2301 |
|
2302 (*------------------------ Miscellaneous function -------------------------- |
|
2303 * |
|
2304 * [x_1,...,x_n] ?v_1...v_n. M[v_1,...,v_n] |
|
2305 * ----------------------------------------------------------- |
|
2306 * ( M[x_1,...,x_n], [(x_i,?v_1...v_n. M[v_1,...,v_n]), |
|
2307 * ... |
|
2308 * (x_j,?v_n. M[x_1,...,x_(n-1),v_n])] ) |
|
2309 * |
|
2310 * This function is totally ad hoc. Used in the production of the induction |
|
2311 * theorem. The nchotomy theorem can have clauses that look like |
|
2312 * |
|
2313 * ?v1..vn. z = C vn..v1 |
|
2314 * |
|
2315 * in which the order of quantification is not the order of occurrence of the |
|
2316 * quantified variables as arguments to C. Since we have no control over this |
|
2317 * aspect of the nchotomy theorem, we make the correspondence explicit by |
|
2318 * pairing the incoming new variable with the term it gets beta-reduced into. |
|
2319 *---------------------------------------------------------------------------*) |
|
2320 |
|
2321 fun alpha_ex_unroll (xlist, tm) = |
|
2322 let val (qvars,body) = USyntax.strip_exists tm |
|
2323 val vlist = #2 (USyntax.strip_comb (USyntax.rhs body)) |
|
2324 val plist = ListPair.zip (vlist, xlist) |
|
2325 val args = map (the o AList.lookup (op aconv) plist) qvars |
|
2326 handle Option.Option => raise Fail "TFL.alpha_ex_unroll: no correspondence" |
|
2327 fun build ex [] = [] |
|
2328 | build (_$rex) (v::rst) = |
|
2329 let val ex1 = Term.betapply(rex, v) |
|
2330 in ex1 :: build ex1 rst |
|
2331 end |
|
2332 val (nex::exl) = rev (tm::build tm args) |
|
2333 in |
|
2334 (nex, ListPair.zip (args, rev exl)) |
|
2335 end; |
|
2336 |
|
2337 |
|
2338 |
|
2339 (*---------------------------------------------------------------------------- |
|
2340 * |
|
2341 * PROVING COMPLETENESS OF PATTERNS |
|
2342 * |
|
2343 *---------------------------------------------------------------------------*) |
|
2344 |
|
2345 fun mk_case ty_info usednames thy = |
|
2346 let |
|
2347 val ctxt = Proof_Context.init_global thy |
|
2348 val divide = ipartition (gvvariant usednames) |
|
2349 val tych = Thry.typecheck thy |
|
2350 fun tych_binding(x,y) = (tych x, tych y) |
|
2351 fun fail s = raise TFL_ERR "mk_case" s |
|
2352 fun mk{rows=[],...} = fail"no rows" |
|
2353 | mk{path=[], rows = [([], (thm, bindings))]} = |
|
2354 Rules.IT_EXISTS ctxt (map tych_binding bindings) thm |
|
2355 | mk{path = u::rstp, rows as (p::_, _)::_} = |
|
2356 let val (pat_rectangle,rights) = ListPair.unzip rows |
|
2357 val col0 = map hd pat_rectangle |
|
2358 val pat_rectangle' = map tl pat_rectangle |
|
2359 in |
|
2360 if (forall is_Free col0) (* column 0 is all variables *) |
|
2361 then let val rights' = map (fn ((thm,theta),v) => (thm,theta@[(u,v)])) |
|
2362 (ListPair.zip (rights, col0)) |
|
2363 in mk{path = rstp, rows = ListPair.zip (pat_rectangle', rights')} |
|
2364 end |
|
2365 else (* column 0 is all constructors *) |
|
2366 let val Type (ty_name,_) = type_of p |
|
2367 in |
|
2368 case (ty_info ty_name) |
|
2369 of NONE => fail("Not a known datatype: "^ty_name) |
|
2370 | SOME{constructors,nchotomy} => |
|
2371 let val thm' = Rules.ISPEC (tych u) nchotomy |
|
2372 val disjuncts = USyntax.strip_disj (concl thm') |
|
2373 val subproblems = divide(constructors, rows) |
|
2374 val groups = map #group subproblems |
|
2375 and new_formals = map #new_formals subproblems |
|
2376 val existentials = ListPair.map alpha_ex_unroll |
|
2377 (new_formals, disjuncts) |
|
2378 val constraints = map #1 existentials |
|
2379 val vexl = map #2 existentials |
|
2380 fun expnd tm (pats,(th,b)) = (pats, (Rules.SUBS ctxt [Rules.ASSUME (tych tm)] th, b)) |
|
2381 val news = map (fn (nf,rows,c) => {path = nf@rstp, |
|
2382 rows = map (expnd c) rows}) |
|
2383 (Utils.zip3 new_formals groups constraints) |
|
2384 val recursive_thms = map mk news |
|
2385 val build_exists = Library.foldr |
|
2386 (fn((x,t), th) => |
|
2387 Rules.CHOOSE ctxt (tych x, Rules.ASSUME (tych t)) th) |
|
2388 val thms' = ListPair.map build_exists (vexl, recursive_thms) |
|
2389 val same_concls = Rules.EVEN_ORS thms' |
|
2390 in Rules.DISJ_CASESL thm' same_concls |
|
2391 end |
|
2392 end end |
|
2393 in mk |
|
2394 end; |
|
2395 |
|
2396 |
|
2397 fun complete_cases thy = |
|
2398 let val ctxt = Proof_Context.init_global thy |
|
2399 val tych = Thry.typecheck thy |
|
2400 val ty_info = Thry.induct_info thy |
|
2401 in fn pats => |
|
2402 let val names = List.foldr Misc_Legacy.add_term_names [] pats |
|
2403 val T = type_of (hd pats) |
|
2404 val aname = singleton (Name.variant_list names) "a" |
|
2405 val vname = singleton (Name.variant_list (aname::names)) "v" |
|
2406 val a = Free (aname, T) |
|
2407 val v = Free (vname, T) |
|
2408 val a_eq_v = HOLogic.mk_eq(a,v) |
|
2409 val ex_th0 = Rules.EXISTS (tych (USyntax.mk_exists{Bvar=v,Body=a_eq_v}), tych a) |
|
2410 (Rules.REFL (tych a)) |
|
2411 val th0 = Rules.ASSUME (tych a_eq_v) |
|
2412 val rows = map (fn x => ([x], (th0,[]))) pats |
|
2413 in |
|
2414 Rules.GEN ctxt (tych a) |
|
2415 (Rules.RIGHT_ASSOC ctxt |
|
2416 (Rules.CHOOSE ctxt (tych v, ex_th0) |
|
2417 (mk_case ty_info (vname::aname::names) |
|
2418 thy {path=[v], rows=rows}))) |
|
2419 end end; |
|
2420 |
|
2421 |
|
2422 (*--------------------------------------------------------------------------- |
|
2423 * Constructing induction hypotheses: one for each recursive call. |
|
2424 * |
|
2425 * Note. R will never occur as a variable in the ind_clause, because |
|
2426 * to do so, it would have to be from a nested definition, and we don't |
|
2427 * allow nested defns to have R variable. |
|
2428 * |
|
2429 * Note. When the context is empty, there can be no local variables. |
|
2430 *---------------------------------------------------------------------------*) |
|
2431 (* |
|
2432 local infix 5 ==> |
|
2433 fun (tm1 ==> tm2) = USyntax.mk_imp{ant = tm1, conseq = tm2} |
|
2434 in |
|
2435 fun build_ih f P (pat,TCs) = |
|
2436 let val globals = USyntax.free_vars_lr pat |
|
2437 fun nested tm = is_some (USyntax.find_term (curry (op aconv) f) tm) |
|
2438 fun dest_TC tm = |
|
2439 let val (cntxt,R_y_pat) = USyntax.strip_imp(#2(USyntax.strip_forall tm)) |
|
2440 val (R,y,_) = USyntax.dest_relation R_y_pat |
|
2441 val P_y = if (nested tm) then R_y_pat ==> P$y else P$y |
|
2442 in case cntxt |
|
2443 of [] => (P_y, (tm,[])) |
|
2444 | _ => let |
|
2445 val imp = USyntax.list_mk_conj cntxt ==> P_y |
|
2446 val lvs = gen_rems (op aconv) (USyntax.free_vars_lr imp, globals) |
|
2447 val locals = #2(Utils.pluck (curry (op aconv) P) lvs) handle Utils.ERR _ => lvs |
|
2448 in (USyntax.list_mk_forall(locals,imp), (tm,locals)) end |
|
2449 end |
|
2450 in case TCs |
|
2451 of [] => (USyntax.list_mk_forall(globals, P$pat), []) |
|
2452 | _ => let val (ihs, TCs_locals) = ListPair.unzip(map dest_TC TCs) |
|
2453 val ind_clause = USyntax.list_mk_conj ihs ==> P$pat |
|
2454 in (USyntax.list_mk_forall(globals,ind_clause), TCs_locals) |
|
2455 end |
|
2456 end |
|
2457 end; |
|
2458 *) |
|
2459 |
|
2460 local infix 5 ==> |
|
2461 fun (tm1 ==> tm2) = USyntax.mk_imp{ant = tm1, conseq = tm2} |
|
2462 in |
|
2463 fun build_ih f (P,SV) (pat,TCs) = |
|
2464 let val pat_vars = USyntax.free_vars_lr pat |
|
2465 val globals = pat_vars@SV |
|
2466 fun nested tm = is_some (USyntax.find_term (curry (op aconv) f) tm) |
|
2467 fun dest_TC tm = |
|
2468 let val (cntxt,R_y_pat) = USyntax.strip_imp(#2(USyntax.strip_forall tm)) |
|
2469 val (R,y,_) = USyntax.dest_relation R_y_pat |
|
2470 val P_y = if (nested tm) then R_y_pat ==> P$y else P$y |
|
2471 in case cntxt |
|
2472 of [] => (P_y, (tm,[])) |
|
2473 | _ => let |
|
2474 val imp = USyntax.list_mk_conj cntxt ==> P_y |
|
2475 val lvs = subtract (op aconv) globals (USyntax.free_vars_lr imp) |
|
2476 val locals = #2(Utils.pluck (curry (op aconv) P) lvs) handle Utils.ERR _ => lvs |
|
2477 in (USyntax.list_mk_forall(locals,imp), (tm,locals)) end |
|
2478 end |
|
2479 in case TCs |
|
2480 of [] => (USyntax.list_mk_forall(pat_vars, P$pat), []) |
|
2481 | _ => let val (ihs, TCs_locals) = ListPair.unzip(map dest_TC TCs) |
|
2482 val ind_clause = USyntax.list_mk_conj ihs ==> P$pat |
|
2483 in (USyntax.list_mk_forall(pat_vars,ind_clause), TCs_locals) |
|
2484 end |
|
2485 end |
|
2486 end; |
|
2487 |
|
2488 (*--------------------------------------------------------------------------- |
|
2489 * This function makes good on the promise made in "build_ih". |
|
2490 * |
|
2491 * Input is tm = "(!y. R y pat ==> P y) ==> P pat", |
|
2492 * TCs = TC_1[pat] ... TC_n[pat] |
|
2493 * thm = ih1 /\ ... /\ ih_n |- ih[pat] |
|
2494 *---------------------------------------------------------------------------*) |
|
2495 fun prove_case ctxt f (tm,TCs_locals,thm) = |
|
2496 let val tych = Thry.typecheck (Proof_Context.theory_of ctxt) |
|
2497 val antc = tych(#ant(USyntax.dest_imp tm)) |
|
2498 val thm' = Rules.SPEC_ALL thm |
|
2499 fun nested tm = is_some (USyntax.find_term (curry (op aconv) f) tm) |
|
2500 fun get_cntxt TC = tych(#ant(USyntax.dest_imp(#2(USyntax.strip_forall(concl TC))))) |
|
2501 fun mk_ih ((TC,locals),th2,nested) = |
|
2502 Rules.GENL ctxt (map tych locals) |
|
2503 (if nested then Rules.DISCH (get_cntxt TC) th2 handle Utils.ERR _ => th2 |
|
2504 else if USyntax.is_imp (concl TC) then Rules.IMP_TRANS TC th2 |
|
2505 else Rules.MP th2 TC) |
|
2506 in |
|
2507 Rules.DISCH antc |
|
2508 (if USyntax.is_imp(concl thm') (* recursive calls in this clause *) |
|
2509 then let val th1 = Rules.ASSUME antc |
|
2510 val TCs = map #1 TCs_locals |
|
2511 val ylist = map (#2 o USyntax.dest_relation o #2 o USyntax.strip_imp o |
|
2512 #2 o USyntax.strip_forall) TCs |
|
2513 val TClist = map (fn(TC,lvs) => (Rules.SPEC_ALL(Rules.ASSUME(tych TC)),lvs)) |
|
2514 TCs_locals |
|
2515 val th2list = map (fn t => Rules.SPEC (tych t) th1) ylist |
|
2516 val nlist = map nested TCs |
|
2517 val triples = Utils.zip3 TClist th2list nlist |
|
2518 val Pylist = map mk_ih triples |
|
2519 in Rules.MP thm' (Rules.LIST_CONJ Pylist) end |
|
2520 else thm') |
|
2521 end; |
|
2522 |
|
2523 |
|
2524 (*--------------------------------------------------------------------------- |
|
2525 * |
|
2526 * x = (v1,...,vn) |- M[x] |
|
2527 * --------------------------------------------- |
|
2528 * ?v1 ... vn. x = (v1,...,vn) |- M[x] |
|
2529 * |
|
2530 *---------------------------------------------------------------------------*) |
|
2531 fun LEFT_ABS_VSTRUCT ctxt tych thm = |
|
2532 let fun CHOOSER v (tm,thm) = |
|
2533 let val ex_tm = USyntax.mk_exists{Bvar=v,Body=tm} |
|
2534 in (ex_tm, Rules.CHOOSE ctxt (tych v, Rules.ASSUME (tych ex_tm)) thm) |
|
2535 end |
|
2536 val [veq] = filter (can USyntax.dest_eq) (#1 (Rules.dest_thm thm)) |
|
2537 val {lhs,rhs} = USyntax.dest_eq veq |
|
2538 val L = USyntax.free_vars_lr rhs |
|
2539 in #2 (fold_rev CHOOSER L (veq,thm)) end; |
|
2540 |
|
2541 |
|
2542 (*---------------------------------------------------------------------------- |
|
2543 * Input : f, R, and [(pat1,TCs1),..., (patn,TCsn)] |
|
2544 * |
|
2545 * Instantiates WF_INDUCTION_THM, getting Sinduct and then tries to prove |
|
2546 * recursion induction (Rinduct) by proving the antecedent of Sinduct from |
|
2547 * the antecedent of Rinduct. |
|
2548 *---------------------------------------------------------------------------*) |
|
2549 fun mk_induction thy {fconst, R, SV, pat_TCs_list} = |
|
2550 let val ctxt = Proof_Context.init_global thy |
|
2551 val tych = Thry.typecheck thy |
|
2552 val Sinduction = Rules.UNDISCH (Rules.ISPEC (tych R) Thms.WF_INDUCTION_THM) |
|
2553 val (pats,TCsl) = ListPair.unzip pat_TCs_list |
|
2554 val case_thm = complete_cases thy pats |
|
2555 val domain = (type_of o hd) pats |
|
2556 val Pname = singleton (Name.variant_list (List.foldr (Library.foldr Misc_Legacy.add_term_names) |
|
2557 [] (pats::TCsl))) "P" |
|
2558 val P = Free(Pname, domain --> HOLogic.boolT) |
|
2559 val Sinduct = Rules.SPEC (tych P) Sinduction |
|
2560 val Sinduct_assumf = USyntax.rand ((#ant o USyntax.dest_imp o concl) Sinduct) |
|
2561 val Rassums_TCl' = map (build_ih fconst (P,SV)) pat_TCs_list |
|
2562 val (Rassums,TCl') = ListPair.unzip Rassums_TCl' |
|
2563 val Rinduct_assum = Rules.ASSUME (tych (USyntax.list_mk_conj Rassums)) |
|
2564 val cases = map (fn pat => Term.betapply (Sinduct_assumf, pat)) pats |
|
2565 val tasks = Utils.zip3 cases TCl' (Rules.CONJUNCTS Rinduct_assum) |
|
2566 val proved_cases = map (prove_case ctxt fconst) tasks |
|
2567 val v = |
|
2568 Free (singleton |
|
2569 (Name.variant_list (List.foldr Misc_Legacy.add_term_names [] (map concl proved_cases))) "v", |
|
2570 domain) |
|
2571 val vtyped = tych v |
|
2572 val substs = map (Rules.SYM o Rules.ASSUME o tych o (curry HOLogic.mk_eq v)) pats |
|
2573 val proved_cases1 = ListPair.map (fn (th,th') => Rules.SUBS ctxt [th]th') |
|
2574 (substs, proved_cases) |
|
2575 val abs_cases = map (LEFT_ABS_VSTRUCT ctxt tych) proved_cases1 |
|
2576 val dant = Rules.GEN ctxt vtyped (Rules.DISJ_CASESL (Rules.ISPEC vtyped case_thm) abs_cases) |
|
2577 val dc = Rules.MP Sinduct dant |
|
2578 val Parg_ty = type_of(#Bvar(USyntax.dest_forall(concl dc))) |
|
2579 val vars = map (gvvariant[Pname]) (USyntax.strip_prod_type Parg_ty) |
|
2580 val dc' = fold_rev (Rules.GEN ctxt o tych) vars |
|
2581 (Rules.SPEC (tych(USyntax.mk_vstruct Parg_ty vars)) dc) |
|
2582 in |
|
2583 Rules.GEN ctxt (tych P) (Rules.DISCH (tych(concl Rinduct_assum)) dc') |
|
2584 end |
|
2585 handle Utils.ERR _ => raise TFL_ERR "mk_induction" "failed derivation"; |
|
2586 |
|
2587 |
|
2588 |
|
2589 |
|
2590 (*--------------------------------------------------------------------------- |
|
2591 * |
|
2592 * POST PROCESSING |
|
2593 * |
|
2594 *---------------------------------------------------------------------------*) |
|
2595 |
|
2596 |
|
2597 fun simplify_induction thy hth ind = |
|
2598 let val tych = Thry.typecheck thy |
|
2599 val (asl,_) = Rules.dest_thm ind |
|
2600 val (_,tc_eq_tc') = Rules.dest_thm hth |
|
2601 val tc = USyntax.lhs tc_eq_tc' |
|
2602 fun loop [] = ind |
|
2603 | loop (asm::rst) = |
|
2604 if (can (Thry.match_term thy asm) tc) |
|
2605 then Rules.UNDISCH |
|
2606 (Rules.MATCH_MP |
|
2607 (Rules.MATCH_MP Thms.simp_thm (Rules.DISCH (tych asm) ind)) |
|
2608 hth) |
|
2609 else loop rst |
|
2610 in loop asl |
|
2611 end; |
|
2612 |
|
2613 |
|
2614 (*--------------------------------------------------------------------------- |
|
2615 * The termination condition is an antecedent to the rule, and an |
|
2616 * assumption to the theorem. |
|
2617 *---------------------------------------------------------------------------*) |
|
2618 fun elim_tc tcthm (rule,induction) = |
|
2619 (Rules.MP rule tcthm, Rules.PROVE_HYP tcthm induction) |
|
2620 |
|
2621 |
|
2622 fun trace_thms ctxt s L = |
|
2623 if !trace then writeln (cat_lines (s :: map (Display.string_of_thm ctxt) L)) |
|
2624 else (); |
|
2625 |
|
2626 fun trace_cterm ctxt s ct = |
|
2627 if !trace then |
|
2628 writeln (cat_lines [s, Syntax.string_of_term ctxt (Thm.term_of ct)]) |
|
2629 else (); |
|
2630 |
|
2631 |
|
2632 fun postprocess ctxt strict {wf_tac, terminator, simplifier} {rules,induction,TCs} = |
|
2633 let |
|
2634 val thy = Proof_Context.theory_of ctxt; |
|
2635 val tych = Thry.typecheck thy; |
|
2636 |
|
2637 (*--------------------------------------------------------------------- |
|
2638 * Attempt to eliminate WF condition. It's the only assumption of rules |
|
2639 *---------------------------------------------------------------------*) |
|
2640 val (rules1,induction1) = |
|
2641 let val thm = |
|
2642 Rules.prove ctxt strict (HOLogic.mk_Trueprop (hd(#1(Rules.dest_thm rules))), wf_tac) |
|
2643 in (Rules.PROVE_HYP thm rules, Rules.PROVE_HYP thm induction) |
|
2644 end handle Utils.ERR _ => (rules,induction); |
|
2645 |
|
2646 (*---------------------------------------------------------------------- |
|
2647 * The termination condition (tc) is simplified to |- tc = tc' (there |
|
2648 * might not be a change!) and then 3 attempts are made: |
|
2649 * |
|
2650 * 1. if |- tc = T, then eliminate it with eqT; otherwise, |
|
2651 * 2. apply the terminator to tc'. If |- tc' = T then eliminate; else |
|
2652 * 3. replace tc by tc' in both the rules and the induction theorem. |
|
2653 *---------------------------------------------------------------------*) |
|
2654 |
|
2655 fun simplify_tc tc (r,ind) = |
|
2656 let val tc1 = tych tc |
|
2657 val _ = trace_cterm ctxt "TC before simplification: " tc1 |
|
2658 val tc_eq = simplifier tc1 |
|
2659 val _ = trace_thms ctxt "result: " [tc_eq] |
|
2660 in |
|
2661 elim_tc (Rules.MATCH_MP Thms.eqT tc_eq) (r,ind) |
|
2662 handle Utils.ERR _ => |
|
2663 (elim_tc (Rules.MATCH_MP(Rules.MATCH_MP Thms.rev_eq_mp tc_eq) |
|
2664 (Rules.prove ctxt strict (HOLogic.mk_Trueprop(USyntax.rhs(concl tc_eq)), |
|
2665 terminator))) |
|
2666 (r,ind) |
|
2667 handle Utils.ERR _ => |
|
2668 (Rules.UNDISCH(Rules.MATCH_MP (Rules.MATCH_MP Thms.simp_thm r) tc_eq), |
|
2669 simplify_induction thy tc_eq ind)) |
|
2670 end |
|
2671 |
|
2672 (*---------------------------------------------------------------------- |
|
2673 * Nested termination conditions are harder to get at, since they are |
|
2674 * left embedded in the body of the function (and in induction |
|
2675 * theorem hypotheses). Our "solution" is to simplify them, and try to |
|
2676 * prove termination, but leave the application of the resulting theorem |
|
2677 * to a higher level. So things go much as in "simplify_tc": the |
|
2678 * termination condition (tc) is simplified to |- tc = tc' (there might |
|
2679 * not be a change) and then 2 attempts are made: |
|
2680 * |
|
2681 * 1. if |- tc = T, then return |- tc; otherwise, |
|
2682 * 2. apply the terminator to tc'. If |- tc' = T then return |- tc; else |
|
2683 * 3. return |- tc = tc' |
|
2684 *---------------------------------------------------------------------*) |
|
2685 fun simplify_nested_tc tc = |
|
2686 let val tc_eq = simplifier (tych (#2 (USyntax.strip_forall tc))) |
|
2687 in |
|
2688 Rules.GEN_ALL ctxt |
|
2689 (Rules.MATCH_MP Thms.eqT tc_eq |
|
2690 handle Utils.ERR _ => |
|
2691 (Rules.MATCH_MP(Rules.MATCH_MP Thms.rev_eq_mp tc_eq) |
|
2692 (Rules.prove ctxt strict (HOLogic.mk_Trueprop (USyntax.rhs(concl tc_eq)), |
|
2693 terminator)) |
|
2694 handle Utils.ERR _ => tc_eq)) |
|
2695 end |
|
2696 |
|
2697 (*------------------------------------------------------------------- |
|
2698 * Attempt to simplify the termination conditions in each rule and |
|
2699 * in the induction theorem. |
|
2700 *-------------------------------------------------------------------*) |
|
2701 fun strip_imp tm = if USyntax.is_neg tm then ([],tm) else USyntax.strip_imp tm |
|
2702 fun loop ([],extras,R,ind) = (rev R, ind, extras) |
|
2703 | loop ((r,ftcs)::rst, nthms, R, ind) = |
|
2704 let val tcs = #1(strip_imp (concl r)) |
|
2705 val extra_tcs = subtract (op aconv) tcs ftcs |
|
2706 val extra_tc_thms = map simplify_nested_tc extra_tcs |
|
2707 val (r1,ind1) = fold simplify_tc tcs (r,ind) |
|
2708 val r2 = Rules.FILTER_DISCH_ALL(not o USyntax.is_WFR) r1 |
|
2709 in loop(rst, nthms@extra_tc_thms, r2::R, ind1) |
|
2710 end |
|
2711 val rules_tcs = ListPair.zip (Rules.CONJUNCTS rules1, TCs) |
|
2712 val (rules2,ind2,extras) = loop(rules_tcs,[],[],induction1) |
|
2713 in |
|
2714 {induction = ind2, rules = Rules.LIST_CONJ rules2, nested_tcs = extras} |
|
2715 end; |
|
2716 |
|
2717 end; |
|
2718 |
|
2719 |
|
2720 (*** second part of main module (postprocessing of TFL definitions) ***) |
|
2721 |
|
2722 structure Tfl: TFL = |
|
2723 struct |
|
2724 |
|
2725 (* misc *) |
|
2726 |
|
2727 (*--------------------------------------------------------------------------- |
|
2728 * Extract termination goals so that they can be put it into a goalstack, or |
|
2729 * have a tactic directly applied to them. |
|
2730 *--------------------------------------------------------------------------*) |
|
2731 fun termination_goals rules = |
|
2732 map (Type.legacy_freeze o HOLogic.dest_Trueprop) |
|
2733 (fold_rev (union (op aconv) o Thm.prems_of) rules []); |
|
2734 |
|
2735 (*--------------------------------------------------------------------------- |
|
2736 * Three postprocessors are applied to the definition. It |
|
2737 * attempts to prove wellfoundedness of the given relation, simplifies the |
|
2738 * non-proved termination conditions, and finally attempts to prove the |
|
2739 * simplified termination conditions. |
|
2740 *--------------------------------------------------------------------------*) |
|
2741 fun std_postprocessor ctxt strict wfs = |
|
2742 Prim.postprocess ctxt strict |
|
2743 {wf_tac = REPEAT (ares_tac wfs 1), |
|
2744 terminator = |
|
2745 asm_simp_tac ctxt 1 |
|
2746 THEN TRY (Arith_Data.arith_tac ctxt 1 ORELSE |
|
2747 fast_force_tac (ctxt addSDs @{thms not0_implies_Suc}) 1), |
|
2748 simplifier = Rules.simpl_conv ctxt []}; |
|
2749 |
|
2750 |
|
2751 |
|
2752 val concl = #2 o Rules.dest_thm; |
|
2753 |
|
2754 (*--------------------------------------------------------------------------- |
|
2755 * Postprocess a definition made by "define". This is a separate stage of |
|
2756 * processing from the definition stage. |
|
2757 *---------------------------------------------------------------------------*) |
|
2758 local |
|
2759 |
|
2760 (* The rest of these local definitions are for the tricky nested case *) |
|
2761 val solved = not o can USyntax.dest_eq o #2 o USyntax.strip_forall o concl |
|
2762 |
|
2763 fun id_thm th = |
|
2764 let val {lhs,rhs} = USyntax.dest_eq (#2 (USyntax.strip_forall (#2 (Rules.dest_thm th)))); |
|
2765 in lhs aconv rhs end |
|
2766 handle Utils.ERR _ => false; |
|
2767 |
|
2768 val P_imp_P_eq_True = @{thm eqTrueI} RS eq_reflection; |
|
2769 fun mk_meta_eq r = |
|
2770 (case Thm.concl_of r of |
|
2771 Const(@{const_name Pure.eq},_)$_$_ => r |
|
2772 | _ $(Const(@{const_name HOL.eq},_)$_$_) => r RS eq_reflection |
|
2773 | _ => r RS P_imp_P_eq_True) |
|
2774 |
|
2775 (*Is this the best way to invoke the simplifier??*) |
|
2776 fun rewrite ctxt L = rewrite_rule ctxt (map mk_meta_eq (filter_out id_thm L)) |
|
2777 |
|
2778 fun join_assums ctxt th = |
|
2779 let val tych = Thm.cterm_of ctxt |
|
2780 val {lhs,rhs} = USyntax.dest_eq(#2 (USyntax.strip_forall (concl th))) |
|
2781 val cntxtl = (#1 o USyntax.strip_imp) lhs (* cntxtl should = cntxtr *) |
|
2782 val cntxtr = (#1 o USyntax.strip_imp) rhs (* but union is solider *) |
|
2783 val cntxt = union (op aconv) cntxtl cntxtr |
|
2784 in |
|
2785 Rules.GEN_ALL ctxt |
|
2786 (Rules.DISCH_ALL |
|
2787 (rewrite ctxt (map (Rules.ASSUME o tych) cntxt) (Rules.SPEC_ALL th))) |
|
2788 end |
|
2789 val gen_all = USyntax.gen_all |
|
2790 in |
|
2791 fun proof_stage ctxt strict wfs {f, R, rules, full_pats_TCs, TCs} = |
|
2792 let |
|
2793 val _ = writeln "Proving induction theorem ..." |
|
2794 val ind = |
|
2795 Prim.mk_induction (Proof_Context.theory_of ctxt) |
|
2796 {fconst=f, R=R, SV=[], pat_TCs_list=full_pats_TCs} |
|
2797 val _ = writeln "Postprocessing ..."; |
|
2798 val {rules, induction, nested_tcs} = |
|
2799 std_postprocessor ctxt strict wfs {rules=rules, induction=ind, TCs=TCs} |
|
2800 in |
|
2801 case nested_tcs |
|
2802 of [] => {induction=induction, rules=rules,tcs=[]} |
|
2803 | L => let val dummy = writeln "Simplifying nested TCs ..." |
|
2804 val (solved,simplified,stubborn) = |
|
2805 fold_rev (fn th => fn (So,Si,St) => |
|
2806 if (id_thm th) then (So, Si, th::St) else |
|
2807 if (solved th) then (th::So, Si, St) |
|
2808 else (So, th::Si, St)) nested_tcs ([],[],[]) |
|
2809 val simplified' = map (join_assums ctxt) simplified |
|
2810 val dummy = (Prim.trace_thms ctxt "solved =" solved; |
|
2811 Prim.trace_thms ctxt "simplified' =" simplified') |
|
2812 val rewr = full_simplify (ctxt addsimps (solved @ simplified')); |
|
2813 val dummy = Prim.trace_thms ctxt "Simplifying the induction rule..." [induction] |
|
2814 val induction' = rewr induction |
|
2815 val dummy = Prim.trace_thms ctxt "Simplifying the recursion rules..." [rules] |
|
2816 val rules' = rewr rules |
|
2817 val _ = writeln "... Postprocessing finished"; |
|
2818 in |
|
2819 {induction = induction', |
|
2820 rules = rules', |
|
2821 tcs = map (gen_all o USyntax.rhs o #2 o USyntax.strip_forall o concl) |
|
2822 (simplified@stubborn)} |
|
2823 end |
|
2824 end; |
|
2825 |
|
2826 |
|
2827 (*lcp: curry the predicate of the induction rule*) |
|
2828 fun curry_rule ctxt rl = |
|
2829 Split_Rule.split_rule_var ctxt (Term.head_of (HOLogic.dest_Trueprop (Thm.concl_of rl))) rl; |
|
2830 |
|
2831 (*lcp: put a theorem into Isabelle form, using meta-level connectives*) |
|
2832 fun meta_outer ctxt = |
|
2833 curry_rule ctxt o Drule.export_without_context o |
|
2834 rule_by_tactic ctxt (REPEAT (FIRSTGOAL (resolve_tac ctxt [allI, impI, conjI] ORELSE' etac conjE))); |
|
2835 |
|
2836 (*Strip off the outer !P*) |
|
2837 val spec'= |
|
2838 Rule_Insts.read_instantiate @{context} [((("x", 0), Position.none), "P::'b=>bool")] [] spec; |
|
2839 |
|
2840 fun tracing true _ = () |
|
2841 | tracing false msg = writeln msg; |
|
2842 |
|
2843 fun simplify_defn ctxt strict congs wfs id pats def0 = |
|
2844 let |
|
2845 val def = Thm.unvarify_global def0 RS meta_eq_to_obj_eq |
|
2846 val {rules, rows, TCs, full_pats_TCs} = Prim.post_definition ctxt congs (def, pats) |
|
2847 val {lhs=f,rhs} = USyntax.dest_eq (concl def) |
|
2848 val (_,[R,_]) = USyntax.strip_comb rhs |
|
2849 val dummy = Prim.trace_thms ctxt "congs =" congs |
|
2850 (*the next step has caused simplifier looping in some cases*) |
|
2851 val {induction, rules, tcs} = |
|
2852 proof_stage ctxt strict wfs |
|
2853 {f = f, R = R, rules = rules, |
|
2854 full_pats_TCs = full_pats_TCs, |
|
2855 TCs = TCs} |
|
2856 val rules' = map (Drule.export_without_context o Object_Logic.rulify_no_asm ctxt) |
|
2857 (Rules.CONJUNCTS rules) |
|
2858 in |
|
2859 {induct = meta_outer ctxt (Object_Logic.rulify_no_asm ctxt (induction RS spec')), |
|
2860 rules = ListPair.zip(rules', rows), |
|
2861 tcs = (termination_goals rules') @ tcs} |
|
2862 end |
|
2863 handle Utils.ERR {mesg,func,module} => |
|
2864 error (mesg ^ "\n (In TFL function " ^ module ^ "." ^ func ^ ")"); |
|
2865 |
|
2866 |
|
2867 (* Derive the initial equations from the case-split rules to meet the |
|
2868 users specification of the recursive function. *) |
|
2869 local |
|
2870 fun get_related_thms i = |
|
2871 map_filter ((fn (r,x) => if x = i then SOME r else NONE)); |
|
2872 |
|
2873 fun solve_eq _ (th, [], i) = error "derive_init_eqs: missing rules" |
|
2874 | solve_eq _ (th, [a], i) = [(a, i)] |
|
2875 | solve_eq ctxt (th, splitths, i) = |
|
2876 (writeln "Proving unsplit equation..."; |
|
2877 [((Drule.export_without_context o Object_Logic.rulify_no_asm ctxt) |
|
2878 (CaseSplit.splitto ctxt splitths th), i)]) |
|
2879 handle ERROR s => |
|
2880 (warning ("recdef (solve_eq): " ^ s); map (fn x => (x,i)) splitths); |
|
2881 in |
|
2882 fun derive_init_eqs ctxt rules eqs = |
|
2883 map (Thm.trivial o Thm.cterm_of ctxt o HOLogic.mk_Trueprop) eqs |
|
2884 |> map_index (fn (i, e) => solve_eq ctxt (e, (get_related_thms i rules), i)) |
|
2885 |> flat; |
|
2886 end; |
|
2887 |
|
2888 |
|
2889 (*--------------------------------------------------------------------------- |
|
2890 * Defining a function with an associated termination relation. |
|
2891 *---------------------------------------------------------------------------*) |
|
2892 fun define_i strict congs wfs fid R eqs ctxt = |
|
2893 let |
|
2894 val thy = Proof_Context.theory_of ctxt |
|
2895 val {functional, pats} = Prim.mk_functional thy eqs |
|
2896 val (def, thy') = Prim.wfrec_definition0 fid R functional thy |
|
2897 val ctxt' = Proof_Context.transfer thy' ctxt |
|
2898 val (lhs, _) = Logic.dest_equals (Thm.prop_of def) |
|
2899 val {induct, rules, tcs} = simplify_defn ctxt' strict congs wfs fid pats def |
|
2900 val rules' = if strict then derive_init_eqs ctxt' rules eqs else rules |
|
2901 in ({lhs = lhs, rules = rules', induct = induct, tcs = tcs}, ctxt') end; |
|
2902 |
|
2903 fun define strict congs wfs fid R seqs ctxt = |
|
2904 define_i strict congs wfs fid |
|
2905 (Syntax.read_term ctxt R) (map (Syntax.read_term ctxt) seqs) ctxt |
|
2906 handle Utils.ERR {mesg,...} => error mesg; |
|
2907 |
|
2908 |
|
2909 (*--------------------------------------------------------------------------- |
|
2910 * |
|
2911 * Definitions with synthesized termination relation |
|
2912 * |
|
2913 *---------------------------------------------------------------------------*) |
|
2914 |
|
2915 fun func_of_cond_eqn tm = |
|
2916 #1 (USyntax.strip_comb (#lhs (USyntax.dest_eq (#2 (USyntax.strip_forall (#2 (USyntax.strip_imp tm))))))); |
|
2917 |
|
2918 fun defer_i congs fid eqs thy = |
|
2919 let |
|
2920 val {rules,R,theory,full_pats_TCs,SV,...} = Prim.lazyR_def thy fid congs eqs |
|
2921 val f = func_of_cond_eqn (concl (Rules.CONJUNCT1 rules handle Utils.ERR _ => rules)); |
|
2922 val dummy = writeln "Proving induction theorem ..."; |
|
2923 val induction = Prim.mk_induction theory |
|
2924 {fconst=f, R=R, SV=SV, pat_TCs_list=full_pats_TCs} |
|
2925 in |
|
2926 (*return the conjoined induction rule and recursion equations, |
|
2927 with assumptions remaining to discharge*) |
|
2928 (Drule.export_without_context (induction RS (rules RS conjI)), theory) |
|
2929 end |
|
2930 |
|
2931 fun defer congs fid seqs thy = |
|
2932 defer_i congs fid (map (Syntax.read_term_global thy) seqs) thy |
|
2933 handle Utils.ERR {mesg,...} => error mesg; |
|
2934 end; |
|
2935 |
|
2936 end; |
|
2937 |
|
2938 |
|
2939 (*** wrappers for Isar ***) |
|
2940 |
|
2941 (** recdef hints **) |
|
2942 |
|
2943 (* type hints *) |
|
2944 |
|
2945 type hints = {simps: thm list, congs: (string * thm) list, wfs: thm list}; |
|
2946 |
|
2947 fun mk_hints (simps, congs, wfs) = {simps = simps, congs = congs, wfs = wfs}: hints; |
|
2948 fun map_hints f ({simps, congs, wfs}: hints) = mk_hints (f (simps, congs, wfs)); |
|
2949 |
|
2950 fun map_simps f = map_hints (fn (simps, congs, wfs) => (f simps, congs, wfs)); |
|
2951 fun map_congs f = map_hints (fn (simps, congs, wfs) => (simps, f congs, wfs)); |
|
2952 fun map_wfs f = map_hints (fn (simps, congs, wfs) => (simps, congs, f wfs)); |
|
2953 |
|
2954 |
|
2955 (* congruence rules *) |
|
2956 |
|
2957 local |
|
2958 |
|
2959 val cong_head = |
|
2960 fst o Term.dest_Const o Term.head_of o fst o Logic.dest_equals o Thm.concl_of; |
|
2961 |
|
2962 fun prep_cong raw_thm = |
|
2963 let val thm = safe_mk_meta_eq raw_thm in (cong_head thm, thm) end; |
|
2964 |
|
2965 in |
|
2966 |
|
2967 fun add_cong raw_thm congs = |
|
2968 let |
|
2969 val (c, thm) = prep_cong raw_thm; |
|
2970 val _ = if AList.defined (op =) congs c |
|
2971 then warning ("Overwriting recdef congruence rule for " ^ quote c) |
|
2972 else (); |
|
2973 in AList.update (op =) (c, thm) congs end; |
|
2974 |
|
2975 fun del_cong raw_thm congs = |
|
2976 let |
|
2977 val (c, thm) = prep_cong raw_thm; |
|
2978 val _ = if AList.defined (op =) congs c |
|
2979 then () |
|
2980 else warning ("No recdef congruence rule for " ^ quote c); |
|
2981 in AList.delete (op =) c congs end; |
|
2982 |
|
2983 end; |
|
2984 |
|
2985 |
|
2986 |
|
2987 (** global and local recdef data **) |
|
2988 |
|
2989 (* theory data *) |
|
2990 |
|
2991 type recdef_info = {lhs: term, simps: thm list, rules: thm list list, induct: thm, tcs: term list}; |
|
2992 |
|
2993 structure Data = Generic_Data |
|
2994 ( |
|
2995 type T = recdef_info Symtab.table * hints; |
|
2996 val empty = (Symtab.empty, mk_hints ([], [], [])): T; |
|
2997 val extend = I; |
|
2998 fun merge |
|
2999 ((tab1, {simps = simps1, congs = congs1, wfs = wfs1}), |
|
3000 (tab2, {simps = simps2, congs = congs2, wfs = wfs2})) : T = |
|
3001 (Symtab.merge (K true) (tab1, tab2), |
|
3002 mk_hints (Thm.merge_thms (simps1, simps2), |
|
3003 AList.merge (op =) (K true) (congs1, congs2), |
|
3004 Thm.merge_thms (wfs1, wfs2))); |
|
3005 ); |
|
3006 |
|
3007 val get_recdef = Symtab.lookup o #1 o Data.get o Context.Theory; |
|
3008 |
|
3009 fun put_recdef name info = |
|
3010 (Context.theory_map o Data.map o apfst) (fn tab => |
|
3011 Symtab.update_new (name, info) tab |
|
3012 handle Symtab.DUP _ => error ("Duplicate recursive function definition " ^ quote name)); |
|
3013 |
|
3014 val get_hints = #2 o Data.get o Context.Proof; |
|
3015 val map_hints = Data.map o apsnd; |
|
3016 |
|
3017 |
|
3018 (* attributes *) |
|
3019 |
|
3020 fun attrib f = Thm.declaration_attribute (map_hints o f); |
|
3021 |
|
3022 val simp_add = attrib (map_simps o Thm.add_thm); |
|
3023 val simp_del = attrib (map_simps o Thm.del_thm); |
|
3024 val cong_add = attrib (map_congs o add_cong); |
|
3025 val cong_del = attrib (map_congs o del_cong); |
|
3026 val wf_add = attrib (map_wfs o Thm.add_thm); |
|
3027 val wf_del = attrib (map_wfs o Thm.del_thm); |
|
3028 |
|
3029 |
|
3030 (* modifiers *) |
|
3031 |
|
3032 val recdef_simpN = "recdef_simp"; |
|
3033 val recdef_congN = "recdef_cong"; |
|
3034 val recdef_wfN = "recdef_wf"; |
|
3035 |
|
3036 val recdef_modifiers = |
|
3037 [Args.$$$ recdef_simpN -- Args.colon >> K (Method.modifier simp_add @{here}), |
|
3038 Args.$$$ recdef_simpN -- Args.add -- Args.colon >> K (Method.modifier simp_add @{here}), |
|
3039 Args.$$$ recdef_simpN -- Args.del -- Args.colon >> K (Method.modifier simp_del @{here}), |
|
3040 Args.$$$ recdef_congN -- Args.colon >> K (Method.modifier cong_add @{here}), |
|
3041 Args.$$$ recdef_congN -- Args.add -- Args.colon >> K (Method.modifier cong_add @{here}), |
|
3042 Args.$$$ recdef_congN -- Args.del -- Args.colon >> K (Method.modifier cong_del @{here}), |
|
3043 Args.$$$ recdef_wfN -- Args.colon >> K (Method.modifier wf_add @{here}), |
|
3044 Args.$$$ recdef_wfN -- Args.add -- Args.colon >> K (Method.modifier wf_add @{here}), |
|
3045 Args.$$$ recdef_wfN -- Args.del -- Args.colon >> K (Method.modifier wf_del @{here})] @ |
|
3046 Clasimp.clasimp_modifiers; |
|
3047 |
|
3048 |
|
3049 |
|
3050 (** prepare hints **) |
|
3051 |
|
3052 fun prepare_hints opt_src ctxt = |
|
3053 let |
|
3054 val ctxt' = |
|
3055 (case opt_src of |
|
3056 NONE => ctxt |
|
3057 | SOME src => #2 (Token.syntax (Method.sections recdef_modifiers) src ctxt)); |
|
3058 val {simps, congs, wfs} = get_hints ctxt'; |
|
3059 val ctxt'' = ctxt' addsimps simps |> Simplifier.del_cong @{thm imp_cong}; |
|
3060 in ((rev (map snd congs), wfs), ctxt'') end; |
|
3061 |
|
3062 fun prepare_hints_i () ctxt = |
|
3063 let |
|
3064 val {simps, congs, wfs} = get_hints ctxt; |
|
3065 val ctxt' = ctxt addsimps simps |> Simplifier.del_cong @{thm imp_cong}; |
|
3066 in ((rev (map snd congs), wfs), ctxt') end; |
|
3067 |
|
3068 |
|
3069 |
|
3070 (** add_recdef(_i) **) |
|
3071 |
|
3072 fun gen_add_recdef tfl_fn prep_att prep_hints not_permissive raw_name R eq_srcs hints thy = |
|
3073 let |
|
3074 val _ = legacy_feature "Old 'recdef' command -- use 'fun' or 'function' instead"; |
|
3075 |
|
3076 val name = Sign.intern_const thy raw_name; |
|
3077 val bname = Long_Name.base_name name; |
|
3078 val _ = writeln ("Defining recursive function " ^ quote name ^ " ..."); |
|
3079 |
|
3080 val ((eq_names, eqs), raw_eq_atts) = apfst split_list (split_list eq_srcs); |
|
3081 val eq_atts = map (map (prep_att thy)) raw_eq_atts; |
|
3082 |
|
3083 val ((congs, wfs), ctxt) = prep_hints hints (Proof_Context.init_global thy); |
|
3084 (*We must remove imp_cong to prevent looping when the induction rule |
|
3085 is simplified. Many induction rules have nested implications that would |
|
3086 give rise to looping conditional rewriting.*) |
|
3087 val ({lhs, rules = rules_idx, induct, tcs}, ctxt1) = |
|
3088 tfl_fn not_permissive congs wfs name R eqs ctxt; |
|
3089 val rules = (map o map) fst (partition_eq (eq_snd (op = : int * int -> bool)) rules_idx); |
|
3090 val simp_att = |
|
3091 if null tcs then [Simplifier.simp_add, |
|
3092 Named_Theorems.add @{named_theorems nitpick_simp}, Code.add_default_eqn_attribute] |
|
3093 else []; |
|
3094 val ((simps' :: rules', [induct']), thy2) = |
|
3095 Proof_Context.theory_of ctxt1 |
|
3096 |> Sign.add_path bname |
|
3097 |> Global_Theory.add_thmss |
|
3098 (((Binding.name "simps", flat rules), simp_att) :: ((eq_names ~~ rules) ~~ eq_atts)) |
|
3099 ||>> Global_Theory.add_thms [((Binding.name "induct", induct), [])] |
|
3100 ||> Spec_Rules.add_global Spec_Rules.Equational ([lhs], flat rules); |
|
3101 val result = {lhs = lhs, simps = simps', rules = rules', induct = induct', tcs = tcs}; |
|
3102 val thy3 = |
|
3103 thy2 |
|
3104 |> put_recdef name result |
|
3105 |> Sign.parent_path; |
|
3106 in (thy3, result) end; |
|
3107 |
|
3108 val add_recdef = gen_add_recdef Tfl.define Attrib.attribute_cmd_global prepare_hints; |
|
3109 fun add_recdef_i x y z w = gen_add_recdef Tfl.define_i (K I) prepare_hints_i x y z w (); |
|
3110 |
|
3111 |
|
3112 |
|
3113 (** defer_recdef(_i) **) |
|
3114 |
|
3115 fun gen_defer_recdef tfl_fn eval_thms raw_name eqs raw_congs thy = |
|
3116 let |
|
3117 val name = Sign.intern_const thy raw_name; |
|
3118 val bname = Long_Name.base_name name; |
|
3119 |
|
3120 val _ = writeln ("Deferred recursive function " ^ quote name ^ " ..."); |
|
3121 |
|
3122 val congs = eval_thms (Proof_Context.init_global thy) raw_congs; |
|
3123 val (induct_rules, thy2) = tfl_fn congs name eqs thy; |
|
3124 val ([induct_rules'], thy3) = |
|
3125 thy2 |
|
3126 |> Sign.add_path bname |
|
3127 |> Global_Theory.add_thms [((Binding.name "induct_rules", induct_rules), [])] |
|
3128 ||> Sign.parent_path; |
|
3129 in (thy3, {induct_rules = induct_rules'}) end; |
|
3130 |
|
3131 val defer_recdef = gen_defer_recdef Tfl.defer Attrib.eval_thms; |
|
3132 val defer_recdef_i = gen_defer_recdef Tfl.defer_i (K I); |
|
3133 |
|
3134 |
|
3135 |
|
3136 (** recdef_tc(_i) **) |
|
3137 |
|
3138 fun gen_recdef_tc prep_att prep_name (bname, raw_atts) raw_name opt_i int lthy = |
|
3139 let |
|
3140 val thy = Proof_Context.theory_of lthy; |
|
3141 val name = prep_name thy raw_name; |
|
3142 val atts = map (prep_att lthy) raw_atts; |
|
3143 val tcs = |
|
3144 (case get_recdef thy name of |
|
3145 NONE => error ("No recdef definition of constant: " ^ quote name) |
|
3146 | SOME {tcs, ...} => tcs); |
|
3147 val i = the_default 1 opt_i; |
|
3148 val tc = nth tcs (i - 1) handle General.Subscript => |
|
3149 error ("No termination condition #" ^ string_of_int i ^ |
|
3150 " in recdef definition of " ^ quote name); |
|
3151 in |
|
3152 Specification.theorem "" NONE (K I) |
|
3153 (Binding.concealed (Binding.name bname), atts) [] [] |
|
3154 (Element.Shows [(Attrib.empty_binding, [(HOLogic.mk_Trueprop tc, [])])]) int lthy |
|
3155 end; |
|
3156 |
|
3157 val recdef_tc = gen_recdef_tc Attrib.check_src Sign.intern_const; |
|
3158 val recdef_tc_i = gen_recdef_tc (K I) (K I); |
|
3159 |
|
3160 |
|
3161 |
|
3162 (** package setup **) |
|
3163 |
|
3164 (* setup theory *) |
|
3165 |
|
3166 val _ = |
|
3167 Theory.setup |
|
3168 (Attrib.setup @{binding recdef_simp} (Attrib.add_del simp_add simp_del) |
|
3169 "declaration of recdef simp rule" #> |
|
3170 Attrib.setup @{binding recdef_cong} (Attrib.add_del cong_add cong_del) |
|
3171 "declaration of recdef cong rule" #> |
|
3172 Attrib.setup @{binding recdef_wf} (Attrib.add_del wf_add wf_del) |
|
3173 "declaration of recdef wf rule"); |
|
3174 |
|
3175 |
|
3176 (* outer syntax *) |
|
3177 |
|
3178 val hints = |
|
3179 @{keyword "("} |-- |
|
3180 Parse.!!! (Parse.position @{keyword "hints"} -- Parse.args --| @{keyword ")"}) |
|
3181 >> uncurry Token.src; |
|
3182 |
|
3183 val recdef_decl = |
|
3184 Scan.optional |
|
3185 (@{keyword "("} -- Parse.!!! (@{keyword "permissive"} -- @{keyword ")"}) >> K false) true -- |
|
3186 Parse.name -- Parse.term -- Scan.repeat1 (Parse_Spec.opt_thm_name ":" -- Parse.prop) |
|
3187 -- Scan.option hints |
|
3188 >> (fn ((((p, f), R), eqs), src) => #1 o add_recdef p f R (map Parse.triple_swap eqs) src); |
|
3189 |
|
3190 val _ = |
|
3191 Outer_Syntax.command @{command_keyword recdef} "define general recursive functions (obsolete TFL)" |
|
3192 (recdef_decl >> Toplevel.theory); |
|
3193 |
|
3194 |
|
3195 val defer_recdef_decl = |
|
3196 Parse.name -- Scan.repeat1 Parse.prop -- |
|
3197 Scan.optional |
|
3198 (@{keyword "("} |-- @{keyword "congs"} |-- Parse.!!! (Parse.xthms1 --| @{keyword ")"})) [] |
|
3199 >> (fn ((f, eqs), congs) => #1 o defer_recdef f eqs congs); |
|
3200 |
|
3201 val _ = |
|
3202 Outer_Syntax.command @{command_keyword defer_recdef} |
|
3203 "defer general recursive functions (obsolete TFL)" |
|
3204 (defer_recdef_decl >> Toplevel.theory); |
|
3205 |
|
3206 val _ = |
|
3207 Outer_Syntax.local_theory_to_proof' @{command_keyword recdef_tc} |
|
3208 "recommence proof of termination condition (obsolete TFL)" |
|
3209 ((Parse_Spec.opt_thm_name ":" >> apfst Binding.name_of) -- Parse.xname -- |
|
3210 Scan.option (@{keyword "("} |-- Parse.nat --| @{keyword ")"}) |
|
3211 >> (fn ((thm_name, name), i) => recdef_tc thm_name name i)); |
|
3212 |
|
3213 end; |