1 (* ========================================================================= *)
2 (* System of tactics (slightly different from any traditional LCF method). *)
4 (* John Harrison, University of Cambridge Computer Laboratory *)
6 (* (c) Copyright, University of Cambridge 1998 *)
7 (* (c) Copyright, John Harrison 1998-2007 *)
8 (* (c) Copyright, Marco Maggesi 2012 *)
9 (* ========================================================================= *)
13 (* ------------------------------------------------------------------------- *)
14 (* The common case of trivial instantiations. *)
15 (* ------------------------------------------------------------------------- *)
17 let null_inst = ([],[],[] :instantiation);;
19 let null_meta = (([]:term list),null_inst);;
21 (* ------------------------------------------------------------------------- *)
22 (* A goal has labelled assumptions, and the hyps are now thms. *)
23 (* ------------------------------------------------------------------------- *)
25 type goal = (string * thm) list * term;;
27 let equals_goal ((a,w):goal) ((a',w'):goal) =
28 forall2 (fun (s,th) (s',th') -> s = s' & equals_thm th th') a a' & w = w';;
30 (* ------------------------------------------------------------------------- *)
31 (* A justification function for a goalstate [A1 ?- g1; ...; An ?- gn], *)
32 (* starting from an initial goal A ?- g, is a function f such that for any *)
33 (* instantiation @: *)
35 (* f(@) [A1@ |- g1@; ...; An@ |- gn@] = A@ |- g@ *)
36 (* ------------------------------------------------------------------------- *)
38 type justification = instantiation -> thm list -> thm;;
40 (* ------------------------------------------------------------------------- *)
41 (* The goalstate stores the subgoals, justification, current instantiation, *)
42 (* and a list of metavariables. *)
43 (* ------------------------------------------------------------------------- *)
45 type goalstate = (term list * instantiation) * goal list * justification;;
47 (* ------------------------------------------------------------------------- *)
48 (* A goalstack is just a list of goalstates. Could go for more... *)
49 (* ------------------------------------------------------------------------- *)
51 type goalstack = goalstate list;;
53 (* ------------------------------------------------------------------------- *)
54 (* A refinement, applied to a goalstate [A1 ?- g1; ...; An ?- gn] *)
55 (* yields a new goalstate with updated justification function, to *)
56 (* give a possibly-more-instantiated version of the initial goal. *)
57 (* ------------------------------------------------------------------------- *)
59 type refinement = goalstate -> goalstate;;
61 (* ------------------------------------------------------------------------- *)
62 (* A tactic, applied to a goal A ?- g, returns: *)
64 (* o A list of new metavariables introduced *)
65 (* o An instantiation (%) *)
66 (* o A list of subgoals *)
67 (* o A justification f such that for any instantiation @ we have *)
68 (* f(@) [A1@ |- g1@; ...; An@ |- gn@] = A(%;@) |- g(%;@) *)
69 (* ------------------------------------------------------------------------- *)
71 type tactic = goal -> goalstate;;
73 type thm_tactic = thm -> tactic;;
75 type thm_tactical = thm_tactic -> thm_tactic;;
77 (* ------------------------------------------------------------------------- *)
78 (* Apply instantiation to a goal. *)
79 (* ------------------------------------------------------------------------- *)
81 let (inst_goal:instantiation->goal->goal) =
83 map (I F_F INSTANTIATE_ALL p) thms,instantiate p w;;
85 (* ------------------------------------------------------------------------- *)
86 (* Perform a sequential composition (left first) of instantiations. *)
87 (* ------------------------------------------------------------------------- *)
89 let (compose_insts :instantiation->instantiation->instantiation) =
90 fun (pats1,tmin1,tyin1) ((pats2,tmin2,tyin2) as i2) ->
91 let tmin = map (instantiate i2 F_F inst tyin2) tmin1
92 and tyin = map (type_subst tyin2 F_F I) tyin1 in
93 let tmin' = filter (fun (_,x) -> not (can (rev_assoc x) tmin)) tmin2
94 and tyin' = filter (fun (_,a) -> not (can (rev_assoc a) tyin)) tyin2 in
95 pats1@pats2,tmin@tmin',tyin@tyin';;
97 (* ------------------------------------------------------------------------- *)
98 (* Construct A,_FALSITY_ |- p; contortion so falsity is the last element. *)
99 (* ------------------------------------------------------------------------- *)
101 let _FALSITY_ = new_definition `_FALSITY_ = F`;;
104 let pth = UNDISCH(fst(EQ_IMP_RULE _FALSITY_))
105 and qth = ASSUME `_FALSITY_` in
106 fun (asl,c) -> PROVE_HYP qth (itlist ADD_ASSUM (rev asl) (CONTR c pth));;
108 (* ------------------------------------------------------------------------- *)
109 (* Validity checking of tactics. This cannot be 100% accurate without making *)
110 (* arbitrary theorems, but "mk_fthm" brings us quite close. *)
111 (* ------------------------------------------------------------------------- *)
113 let (VALID:tactic->tactic) =
114 let fake_thm (asl,w) =
115 let asms = itlist (union o hyp o snd) asl [] in
117 and false_tm = `_FALSITY_` in
119 let ((mvs,i),gls,just as res) = tac (asl,w) in
120 let ths = map fake_thm gls in
121 let asl',w' = dest_thm(just null_inst ths) in
122 let asl'',w'' = inst_goal i (asl,w) in
124 itlist (fun (_,th) -> union (insert (concl th) (hyp th))) asl'' [] in
126 forall (fun t -> exists (aconv t) maxasms) (subtract asl' [false_tm])
127 then res else failwith "VALID: Invalid tactic";;
129 (* ------------------------------------------------------------------------- *)
130 (* Various simple combinators for tactics, identity tactic etc. *)
131 (* ------------------------------------------------------------------------- *)
134 let propagate_empty i [] = []
135 and propagate_thm th i [] = INSTANTIATE_ALL i th in
136 let compose_justs n just1 just2 i ths =
137 let ths1,ths2 = chop_list n ths in
138 (just1 i ths1)::(just2 i ths2) in
139 let rec seqapply l1 l2 = match (l1,l2) with
140 ([],[]) -> null_meta,[],propagate_empty
141 | ((tac:tactic)::tacs),((goal:goal)::goals) ->
142 let ((mvs1,insts1),gls1,just1) = tac goal in
143 let goals' = map (inst_goal insts1) goals in
144 let ((mvs2,insts2),gls2,just2) = seqapply tacs goals' in
145 ((union mvs1 mvs2,compose_insts insts1 insts2),
146 gls1@gls2,compose_justs (length gls1) just1 just2)
147 | _,_ -> failwith "seqapply: Length mismatch" in
148 let justsequence just1 just2 insts2 i ths =
149 just1 (compose_insts insts2 i) (just2 i ths) in
150 let tacsequence ((mvs1,insts1),gls1,just1) tacl =
151 let ((mvs2,insts2),gls2,just2) = seqapply tacl gls1 in
152 let jst = justsequence just1 just2 insts2 in
153 let just = if gls2 = [] then propagate_thm (jst null_inst []) else jst in
154 ((union mvs1 mvs2,compose_insts insts1 insts2),gls2,just) in
155 let (then_: tactic -> tactic -> tactic) =
157 let _,gls,_ as gstate = tac1 g in
158 tacsequence gstate (replicate tac2 (length gls))
159 and (thenl_: tactic -> tactic list -> tactic) =
161 let _,gls,_ as gstate = tac1 g in
162 if gls = [] then tacsequence gstate []
163 else tacsequence gstate tac2l in
166 let ((ORELSE): tactic -> tactic -> tactic) =
168 try tac1 g with Failure _ -> tac2 g;;
170 let (FAIL_TAC: string -> tactic) =
171 fun tok g -> failwith tok;;
173 let (NO_TAC: tactic) =
176 let (ALL_TAC:tactic) =
177 fun g -> null_meta,[g],fun _ [th] -> th;;
182 let rec REPEAT tac g =
183 ((tac THEN REPEAT tac) ORELSE ALL_TAC) g;;
186 itlist (fun t1 t2 -> t1 THEN t2) tacl ALL_TAC;;
188 let (FIRST: tactic list -> tactic) =
189 fun tacl g -> end_itlist (fun t1 t2 -> t1 ORELSE t2) tacl g;;
191 let MAP_EVERY tacf lst =
192 EVERY (map tacf lst);;
194 let MAP_FIRST tacf lst =
195 FIRST (map tacf lst);;
197 let (CHANGED_TAC: tactic -> tactic) =
199 let (meta,gl,_ as gstate) = tac g in
200 if meta = null_meta & length gl = 1 & equals_goal (hd gl) g
201 then failwith "CHANGED_TAC" else gstate;;
203 let rec REPLICATE_TAC n tac =
204 if n <= 0 then ALL_TAC else tac THEN (REPLICATE_TAC (n - 1) tac);;
206 (* ------------------------------------------------------------------------- *)
207 (* Combinators for theorem continuations / "theorem tacticals". *)
208 (* ------------------------------------------------------------------------- *)
210 let ((THEN_TCL): thm_tactical -> thm_tactical -> thm_tactical) =
211 fun ttcl1 ttcl2 ttac -> ttcl1 (ttcl2 ttac);;
213 let ((ORELSE_TCL): thm_tactical -> thm_tactical -> thm_tactical) =
214 fun ttcl1 ttcl2 ttac th ->
215 try ttcl1 ttac th with Failure _ -> ttcl2 ttac th;;
217 let rec REPEAT_TCL ttcl ttac th =
218 ((ttcl THEN_TCL (REPEAT_TCL ttcl)) ORELSE_TCL I) ttac th;;
220 let (REPEAT_GTCL: thm_tactical -> thm_tactical) =
221 let rec REPEAT_GTCL ttcl ttac th g =
222 try ttcl (REPEAT_GTCL ttcl ttac) th g with Failure _ -> ttac th g in
225 let (ALL_THEN: thm_tactical) =
228 let (NO_THEN: thm_tactical) =
229 fun ttac th -> failwith "NO_THEN";;
231 let EVERY_TCL ttcll =
232 itlist (fun t1 t2 -> t1 THEN_TCL t2) ttcll ALL_THEN;;
234 let FIRST_TCL ttcll =
235 end_itlist (fun t1 t2 -> t1 ORELSE_TCL t2) ttcll;;
237 (* ------------------------------------------------------------------------- *)
238 (* Tactics to augment assumption list. Note that to allow "ASSUME p" for *)
239 (* any assumption "p", these add a PROVE_HYP in the justification function, *)
241 (* ------------------------------------------------------------------------- *)
243 let (LABEL_TAC: string -> thm_tactic) =
245 null_meta,[(s,thm)::asl,w],
246 fun i [th] -> PROVE_HYP (INSTANTIATE_ALL i thm) th;;
248 let ASSUME_TAC = LABEL_TAC "";;
250 (* ------------------------------------------------------------------------- *)
251 (* Manipulation of assumption list. *)
252 (* ------------------------------------------------------------------------- *)
254 let (FIND_ASSUM: thm_tactic -> term -> tactic) =
255 fun ttac t ((asl,w) as g) ->
256 ttac(snd(find (fun (_,th) -> concl th = t) asl)) g;;
258 let (POP_ASSUM: thm_tactic -> tactic) =
260 function (((_,th)::asl),w) -> ttac th (asl,w)
261 | _ -> failwith "POP_ASSUM: No assumption to pop";;
263 let (ASSUM_LIST: (thm list -> tactic) -> tactic) =
264 fun aslfun (asl,w) -> aslfun (map snd asl) (asl,w);;
266 let (POP_ASSUM_LIST: (thm list -> tactic) -> tactic) =
267 fun asltac (asl,w) -> asltac (map snd asl) ([],w);;
269 let (EVERY_ASSUM: thm_tactic -> tactic) =
270 fun ttac -> ASSUM_LIST (MAP_EVERY ttac);;
272 let (FIRST_ASSUM: thm_tactic -> tactic) =
273 fun ttac (asl,w as g) -> tryfind (fun (_,th) -> ttac th g) asl;;
275 let (RULE_ASSUM_TAC :(thm->thm)->tactic) =
276 fun rule (asl,w) -> (POP_ASSUM_LIST(K ALL_TAC) THEN
277 MAP_EVERY (fun (s,th) -> LABEL_TAC s (rule th))
280 (* ------------------------------------------------------------------------- *)
281 (* Operate on assumption identified by a label. *)
282 (* ------------------------------------------------------------------------- *)
284 let (USE_THEN:string->thm_tactic->tactic) =
285 fun s ttac (asl,w as gl) ->
286 let th = try assoc s asl with Failure _ ->
287 failwith("USE_TAC: didn't find assumption "^s) in
290 let (REMOVE_THEN:string->thm_tactic->tactic) =
291 fun s ttac (asl,w) ->
292 let th = try assoc s asl with Failure _ ->
293 failwith("USE_TAC: didn't find assumption "^s) in
294 let asl1,asl2 = chop_list(index s (map fst asl)) asl in
295 let asl' = asl1 @ tl asl2 in
298 (* ------------------------------------------------------------------------- *)
299 (* General tools to augment a required set of theorems with assumptions. *)
300 (* Here ASM uses all current hypotheses of the goal, while HYP uses only *)
301 (* those whose labels are given in the string argument. *)
302 (* ------------------------------------------------------------------------- *)
304 let (ASM :(thm list -> tactic)->(thm list -> tactic)) =
305 fun tltac ths (asl,w as g) -> tltac (map snd asl @ ths) g;;
309 Ident s::rest when isalnum s -> s,rest
310 | _ -> raise Noparse in
311 let parse_using = many ident in
313 rev_itlist (fun s k l -> USE_THEN s (fun th -> k (th::l))) l tac in
315 let l,rest = (fix "Using pattern" parse_using o lex o explode) s in
316 if rest=[] then HYP_LIST tac l else failwith "Invalid using pattern";;
318 (* ------------------------------------------------------------------------- *)
319 (* Basic tactic to use a theorem equal to the goal. Does *no* matching. *)
320 (* ------------------------------------------------------------------------- *)
322 let (ACCEPT_TAC: thm_tactic) =
323 let propagate_thm th i [] = INSTANTIATE_ALL i th in
325 if aconv (concl th) w then
326 null_meta,[],propagate_thm th
327 else failwith "ACCEPT_TAC";;
329 (* ------------------------------------------------------------------------- *)
330 (* Create tactic from a conversion. This allows the conversion to return *)
331 (* |- p rather than |- p = T on a term "p". It also eliminates any goals of *)
332 (* the form "T" automatically. *)
333 (* ------------------------------------------------------------------------- *)
335 let (CONV_TAC: conv -> tactic) =
337 fun conv ((asl,w) as g) ->
340 if aconv tm w then ACCEPT_TAC th g else
341 let l,r = dest_eq tm in
342 if not(aconv l w) then failwith "CONV_TAC: bad equation" else
343 if r = t_tm then ACCEPT_TAC(EQT_ELIM th) g else
345 null_meta,[asl,r],fun i [th] -> EQ_MP (INSTANTIATE_ALL i th') th;;
347 (* ------------------------------------------------------------------------- *)
348 (* Tactics for equality reasoning. *)
349 (* ------------------------------------------------------------------------- *)
351 let (REFL_TAC: tactic) =
352 fun ((asl,w) as g) ->
353 try ACCEPT_TAC(REFL(rand w)) g
354 with Failure _ -> failwith "REFL_TAC";;
356 let (ABS_TAC: tactic) =
358 try let l,r = dest_eq w in
359 let lv,lb = dest_abs l
360 and rv,rb = dest_abs r in
361 let avoids = itlist (union o thm_frees o snd) asl (frees w) in
362 let v = mk_primed_var avoids lv in
363 null_meta,[asl,mk_eq(vsubst[v,lv] lb,vsubst[v,rv] rb)],
364 fun i [th] -> let ath = ABS v th in
365 EQ_MP (ALPHA (concl ath) (instantiate i w)) ath
366 with Failure _ -> failwith "ABS_TAC";;
368 let (MK_COMB_TAC: tactic) =
370 try let l,r = dest_eq gl in
371 let f,x = dest_comb l
372 and g,y = dest_comb r in
373 null_meta,[asl,mk_eq(f,g); asl,mk_eq(x,y)],
374 fun _ [th1;th2] -> MK_COMB(th1,th2)
375 with Failure _ -> failwith "MK_COMB_TAC";;
377 let (AP_TERM_TAC: tactic) =
378 let tac = MK_COMB_TAC THENL [REFL_TAC; ALL_TAC] in
379 fun gl -> try tac gl with Failure _ -> failwith "AP_TERM_TAC";;
381 let (AP_THM_TAC: tactic) =
382 let tac = MK_COMB_TAC THENL [ALL_TAC; REFL_TAC] in
383 fun gl -> try tac gl with Failure _ -> failwith "AP_THM_TAC";;
385 let (BINOP_TAC: tactic) =
386 let tac = MK_COMB_TAC THENL [AP_TERM_TAC; ALL_TAC] in
387 fun gl -> try tac gl with Failure _ -> failwith "AP_THM_TAC";;
389 let (SUBST1_TAC: thm_tactic) =
390 fun th -> CONV_TAC(SUBS_CONV [th]);;
392 let SUBST_ALL_TAC rth =
393 SUBST1_TAC rth THEN RULE_ASSUM_TAC (SUBS [rth]);;
395 let BETA_TAC = CONV_TAC(REDEPTH_CONV BETA_CONV);;
397 (* ------------------------------------------------------------------------- *)
398 (* Just use an equation to substitute if possible and uninstantiable. *)
399 (* ------------------------------------------------------------------------- *)
401 let SUBST_VAR_TAC th =
402 try let asm,eq = dest_thm th in
403 let l,r = dest_eq eq in
404 if aconv l r then ALL_TAC
405 else if not (subset (frees eq) (freesl asm)) then fail()
406 else if (is_const l or is_var l) & not(free_in l r)
407 then SUBST_ALL_TAC th
408 else if (is_const r or is_var r) & not(free_in r l)
409 then SUBST_ALL_TAC(SYM th)
411 with Failure _ -> failwith "SUBST_VAR_TAC";;
413 (* ------------------------------------------------------------------------- *)
414 (* Basic logical tactics. *)
415 (* ------------------------------------------------------------------------- *)
417 let (DISCH_TAC: tactic) =
420 try let ant,c = dest_imp w in
421 let th1 = ASSUME ant in
422 null_meta,[("",th1)::asl,c],
423 fun i [th] -> DISCH (instantiate i ant) th
424 with Failure _ -> try
425 let ant = dest_neg w in
426 let th1 = ASSUME ant in
427 null_meta,[("",th1)::asl,f_tm],
428 fun i [th] -> NOT_INTRO(DISCH (instantiate i ant) th)
429 with Failure _ -> failwith "DISCH_TAC";;
431 let (MP_TAC: thm_tactic) =
433 null_meta,[asl,mk_imp(concl thm,w)],
434 fun i [th] -> MP th (INSTANTIATE_ALL i thm);;
436 let (EQ_TAC: tactic) =
438 try let l,r = dest_eq w in
439 null_meta,[asl, mk_imp(l,r); asl, mk_imp(r,l)],
440 fun _ [th1; th2] -> IMP_ANTISYM_RULE th1 th2
441 with Failure _ -> failwith "EQ_TAC";;
443 let (UNDISCH_TAC: term -> tactic) =
445 try let sthm,asl' = remove (fun (_,asm) -> aconv (concl asm) tm) asl in
446 let thm = snd sthm in
447 null_meta,[asl',mk_imp(tm,w)],
448 fun i [th] -> MP th (INSTANTIATE_ALL i thm)
449 with Failure _ -> failwith "UNDISCH_TAC";;
451 let (SPEC_TAC: term * term -> tactic) =
453 try null_meta,[asl, mk_forall(x,subst[x,t] w)],
454 fun i [th] -> SPEC (instantiate i t) th
455 with Failure _ -> failwith "SPEC_TAC";;
457 let (X_GEN_TAC: term -> tactic),
458 (X_CHOOSE_TAC: term -> thm_tactic),
459 (EXISTS_TAC: term -> tactic) =
460 let tactic_type_compatibility_check pfx e g =
461 let et = type_of e and gt = type_of g in
463 else failwith(pfx ^ ": expected type :"^string_of_type et^" but got :"^
464 string_of_type gt) in
466 if not(is_var x') then failwith "X_GEN_TAC: not a variable" else
468 let x,bod = try dest_forall w
469 with Failure _ -> failwith "X_GEN_TAC: Not universally quantified" in
470 let _ = tactic_type_compatibility_check "X_GEN_TAC" x x' in
471 let avoids = itlist (union o thm_frees o snd) asl (frees w) in
472 if mem x' avoids then failwith "X_GEN_TAC: invalid variable" else
473 let afn = CONV_RULE(GEN_ALPHA_CONV x) in
474 null_meta,[asl,vsubst[x',x] bod],
475 fun i [th] -> afn (GEN x' th)
476 and X_CHOOSE_TAC x' xth =
477 let xtm = concl xth in
478 let x,bod = try dest_exists xtm
479 with Failure _ -> failwith "X_CHOOSE_TAC: not existential" in
480 let _ = tactic_type_compatibility_check "X_CHOOSE_TAC" x x' in
481 let pat = vsubst[x',x] bod in
482 let xth' = ASSUME pat in
484 let avoids = itlist (union o frees o concl o snd) asl
485 (union (frees w) (thm_frees xth)) in
486 if mem x' avoids then failwith "X_CHOOSE_TAC: invalid variable" else
487 null_meta,[("",xth')::asl,w],
488 fun i [th] -> CHOOSE(x',INSTANTIATE_ALL i xth) th
489 and EXISTS_TAC t (asl,w) =
490 let v,bod = try dest_exists w with Failure _ ->
491 failwith "EXISTS_TAC: Goal not existentially quantified" in
492 let _ = tactic_type_compatibility_check "EXISTS_TAC" v t in
493 null_meta,[asl,vsubst[t,v] bod],
494 fun i [th] -> EXISTS (instantiate i w,instantiate i t) th in
495 X_GEN_TAC,X_CHOOSE_TAC,EXISTS_TAC;;
497 let (GEN_TAC: tactic) =
499 try let x = fst(dest_forall w) in
500 let avoids = itlist (union o thm_frees o snd) asl (frees w) in
501 let x' = mk_primed_var avoids x in
503 with Failure _ -> failwith "GEN_TAC";;
505 let (CHOOSE_TAC: thm_tactic) =
507 try let x = fst(dest_exists(concl xth)) in
509 let avoids = itlist (union o thm_frees o snd) asl
510 (union (frees w) (thm_frees xth)) in
511 let x' = mk_primed_var avoids x in
512 X_CHOOSE_TAC x' xth (asl,w)
513 with Failure _ -> failwith "CHOOSE_TAC";;
515 let (CONJ_TAC: tactic) =
517 try let l,r = dest_conj w in
518 null_meta,[asl,l; asl,r],fun _ [th1;th2] -> CONJ th1 th2
519 with Failure _ -> failwith "CONJ_TAC";;
521 let (DISJ1_TAC: tactic) =
523 try let l,r = dest_disj w in
524 null_meta,[asl,l],fun i [th] -> DISJ1 th (instantiate i r)
525 with Failure _ -> failwith "DISJ1_TAC";;
527 let (DISJ2_TAC: tactic) =
529 try let l,r = dest_disj w in
530 null_meta,[asl,r],fun i [th] -> DISJ2 (instantiate i l) th
531 with Failure _ -> failwith "DISJ2_TAC";;
533 let (DISJ_CASES_TAC: thm_tactic) =
535 try let dtm = concl dth in
536 let l,r = dest_disj dtm in
538 and thr = ASSUME r in
540 null_meta,[("",thl)::asl,w; ("",thr)::asl,w],
541 fun i [th1;th2] -> DISJ_CASES (INSTANTIATE_ALL i dth) th1 th2
542 with Failure _ -> failwith "DISJ_CASES_TAC";;
544 let (CONTR_TAC: thm_tactic) =
545 let propagate_thm th i [] = INSTANTIATE_ALL i th in
547 try let th = CONTR w cth in
548 null_meta,[],propagate_thm th
549 with Failure _ -> failwith "CONTR_TAC";;
551 let (MATCH_ACCEPT_TAC:thm_tactic) =
552 let propagate_thm th i [] = INSTANTIATE_ALL i th in
553 let rawtac th (asl,w) =
554 try let ith = PART_MATCH I th w in
555 null_meta,[],propagate_thm ith
556 with Failure _ -> failwith "ACCEPT_TAC" in
557 fun th -> REPEAT GEN_TAC THEN rawtac th;;
559 let (MATCH_MP_TAC :thm_tactic) =
562 try let tm = concl th in
563 let avs,bod = strip_forall tm in
564 let ant,con = dest_imp bod in
565 let th1 = SPECL avs (ASSUME tm) in
566 let th2 = UNDISCH th1 in
567 let evs = filter (fun v -> vfree_in v ant & not (vfree_in v con))
569 let th3 = itlist SIMPLE_CHOOSE evs (DISCH tm th2) in
570 let tm3 = hd(hyp th3) in
571 MP (DISCH tm (GEN_ALL (DISCH tm3 (UNDISCH th3)))) th
572 with Failure _ -> failwith "MATCH_MP_TAC: Bad theorem" in
573 let match_fun = PART_MATCH (snd o dest_imp) sth in
574 fun (asl,w) -> try let xth = match_fun w in
575 let lant = fst(dest_imp(concl xth)) in
576 null_meta,[asl,lant],
577 fun i [th] -> MP (INSTANTIATE_ALL i xth) th
578 with Failure _ -> failwith "MATCH_MP_TAC: No match";;
580 let (TRANS_TAC:thm->term->tactic) =
582 let ctm = snd(strip_forall(concl th)) in
583 let cl,cr = dest_conj(lhand ctm) in
584 let x = lhand cl and y = rand cl and z = rand cr in
585 fun tm (asl,w as gl) ->
586 let lop,r = dest_comb w in
587 let op,l = dest_comb lop in
589 itlist2 type_match (map type_of [x;y;z])(map type_of [l;tm;r]) [] in
590 let th' = INST_TYPE ilist th in
591 (MATCH_MP_TAC th' THEN EXISTS_TAC tm) gl;;
593 (* ------------------------------------------------------------------------- *)
594 (* Theorem continuations. *)
595 (* ------------------------------------------------------------------------- *)
597 let (CONJUNCTS_THEN2:thm_tactic->thm_tactic->thm_tactic) =
598 fun ttac1 ttac2 cth ->
599 let c1,c2 = dest_conj(concl cth) in
600 fun gl -> let ti,gls,jfn = (ttac1(ASSUME c1) THEN ttac2(ASSUME c2)) gl in
602 let th1,th2 = CONJ_PAIR(INSTANTIATE_ALL i cth) in
603 PROVE_HYP th1 (PROVE_HYP th2 (jfn i ths)) in
606 let (CONJUNCTS_THEN: thm_tactical) =
609 let (DISJ_CASES_THEN2:thm_tactic->thm_tactic->thm_tactic) =
610 fun ttac1 ttac2 cth ->
611 DISJ_CASES_TAC cth THENL [POP_ASSUM ttac1; POP_ASSUM ttac2];;
613 let (DISJ_CASES_THEN: thm_tactical) =
616 let (DISCH_THEN: thm_tactic -> tactic) =
617 fun ttac -> DISCH_TAC THEN POP_ASSUM ttac;;
619 let (X_CHOOSE_THEN: term -> thm_tactical) =
620 fun x ttac th -> X_CHOOSE_TAC x th THEN POP_ASSUM ttac;;
622 let (CHOOSE_THEN: thm_tactical) =
623 fun ttac th -> CHOOSE_TAC th THEN POP_ASSUM ttac;;
625 (* ------------------------------------------------------------------------- *)
626 (* Various derived tactics and theorem continuations. *)
627 (* ------------------------------------------------------------------------- *)
630 FIRST_TCL [CONJUNCTS_THEN; DISJ_CASES_THEN; CHOOSE_THEN];;
632 let (ANTE_RES_THEN: thm_tactical) =
636 let tacs = mapfilter (fun imp -> ttac (MATCH_MP imp ante)) asl in
637 if tacs = [] then failwith "IMP_RES_THEN"
640 let (IMP_RES_THEN: thm_tactical) =
644 let tacs = mapfilter (fun ante -> ttac (MATCH_MP imp ante)) asl in
645 if tacs = [] then failwith "IMP_RES_THEN"
648 let STRIP_ASSUME_TAC =
652 if exists (fun a -> aconv tm (concl(snd a))) asl then ALL_TAC g
653 else failwith "DISCARD_TAC: not already present" in
654 (REPEAT_TCL STRIP_THM_THEN)
655 (fun gth -> FIRST [CONTR_TAC gth; ACCEPT_TAC gth;
656 DISCARD_TAC gth; ASSUME_TAC gth]);;
658 let STRUCT_CASES_THEN ttac = REPEAT_TCL STRIP_THM_THEN ttac;;
660 let STRUCT_CASES_TAC = STRUCT_CASES_THEN
661 (fun th -> SUBST1_TAC th ORELSE ASSUME_TAC th);;
663 let STRIP_GOAL_THEN ttac = FIRST [GEN_TAC; CONJ_TAC; DISCH_THEN ttac];;
665 let (STRIP_TAC: tactic) =
667 try STRIP_GOAL_THEN STRIP_ASSUME_TAC g
668 with Failure _ -> failwith "STRIP_TAC";;
670 let (UNDISCH_THEN:term->thm_tactic->tactic) =
671 fun tm ttac (asl,w) ->
672 let thp,asl' = remove (fun (_,th) -> aconv (concl th) tm) asl in
673 ttac (snd thp) (asl',w);;
675 let FIRST_X_ASSUM ttac =
676 FIRST_ASSUM(fun th -> UNDISCH_THEN (concl th) ttac);;
678 (* ------------------------------------------------------------------------- *)
679 (* Subgoaling and freezing variables (latter is especially useful now). *)
680 (* ------------------------------------------------------------------------- *)
682 let (SUBGOAL_THEN: term -> thm_tactic -> tactic) =
683 fun wa ttac (asl,w) ->
684 let meta,gl,just = ttac (ASSUME wa) (asl,w) in
685 meta,(asl,wa)::gl,fun i l -> PROVE_HYP (hd l) (just i (tl l));;
687 let SUBGOAL_TAC s tm prfs =
689 p::ps -> (warn (ps <> []) "SUBGOAL_TAC: additional subproofs ignored";
690 SUBGOAL_THEN tm (LABEL_TAC s) THENL [p; ALL_TAC])
691 | [] -> failwith "SUBGOAL_TAC: no subproof given";;
693 let (FREEZE_THEN :thm_tactical) =
694 fun ttac th (asl,w) ->
695 let meta,gl,just = ttac (ASSUME(concl th)) (asl,w) in
696 meta,gl,fun i l -> PROVE_HYP th (just i l);;
698 (* ------------------------------------------------------------------------- *)
699 (* Metavariable tactics. *)
700 (* ------------------------------------------------------------------------- *)
702 let (X_META_EXISTS_TAC: term -> tactic) =
704 try if not (is_var t) then fail() else
705 let v,bod = dest_exists w in
706 ([t],null_inst),[asl,vsubst[t,v] bod],
707 fun i [th] -> EXISTS (instantiate i w,instantiate i t) th
708 with Failure _ -> failwith "X_META_EXISTS_TAC";;
710 let META_EXISTS_TAC ((asl,w) as gl) =
711 let v = fst(dest_exists w) in
712 let avoids = itlist (union o frees o concl o snd) asl (frees w) in
713 let v' = mk_primed_var avoids v in
714 X_META_EXISTS_TAC v' gl;;
716 let (META_SPEC_TAC: term -> thm -> tactic) =
718 let sth = SPEC t thm in
719 ([t],null_inst),[(("",sth)::asl),w],
720 fun i [th] -> PROVE_HYP (SPEC (instantiate i t) thm) th;;
722 (* ------------------------------------------------------------------------- *)
723 (* If all else fails! *)
724 (* ------------------------------------------------------------------------- *)
726 let (CHEAT_TAC:tactic) =
727 fun (asl,w) -> ACCEPT_TAC(mk_thm([],w)) (asl,w);;
729 (* ------------------------------------------------------------------------- *)
730 (* Intended for time-consuming rules; delays evaluation till it sees goal. *)
731 (* ------------------------------------------------------------------------- *)
733 let RECALL_ACCEPT_TAC r a g = ACCEPT_TAC(time r a) g;;
735 (* ------------------------------------------------------------------------- *)
736 (* Split off antecedent of antecedent as a subgoal. *)
737 (* ------------------------------------------------------------------------- *)
740 let tm1 = `p /\ (q ==> r)`
741 and tm2 = `p ==> q` in
742 let th1,th2 = CONJ_PAIR(ASSUME tm1) in
743 let th = itlist DISCH [tm1;tm2] (MP th2 (MP(ASSUME tm2) th1)) in
744 MATCH_MP_TAC th THEN CONJ_TAC;;
746 (* ------------------------------------------------------------------------- *)
747 (* A printer for goals etc. *)
748 (* ------------------------------------------------------------------------- *)
750 let (print_goal:goal->unit) =
751 let string_of_int3 n =
752 if n < 10 then " "^string_of_int n
753 else if n < 100 then " "^string_of_int n
754 else string_of_int n in
755 let print_hyp n (s,th) =
757 Format.print_string(string_of_int3 n);
758 Format.print_string " [";
760 print_qterm (concl th);
762 Format.print_string "]";
763 (if not (s = "") then (Format.print_string (" ("^s^")")) else ());
765 Format.print_newline() in
766 let rec print_hyps n asl =
767 if asl = [] then () else
768 (print_hyp n (hd asl);
769 print_hyps (n + 1) (tl asl)) in
771 Format.print_newline();
772 if asl <> [] then (print_hyps 0 (rev asl); Format.print_newline()) else ();
773 print_qterm w; Format.print_newline();;
775 let (print_goalstack:goalstack->unit) =
776 let print_goalstate k gs =
779 let s = if n = 0 then "No subgoals" else
780 (string_of_int k)^" subgoal"^(if k > 1 then "s" else "")
781 ^" ("^(string_of_int n)^" total)" in
782 Format.print_string s; Format.print_newline();
783 if gl = [] then () else
784 do_list (print_goal o C el gl) (rev(0--(k-1))) in
786 if l = [] then Format.print_string "Empty goalstack"
787 else if tl l = [] then
788 let (_,gl,_ as gs) = hd l in
791 let (_,gl,_ as gs) = hd l
792 and (_,gl0,_) = hd(tl l) in
793 let p = length gl - length gl0 in
794 let p' = if p < 1 then 1 else p + 1 in
795 print_goalstate p' gs;;
797 (* ------------------------------------------------------------------------- *)
798 (* Convert a tactic into a refinement on head subgoal in current state. *)
799 (* ------------------------------------------------------------------------- *)
801 let (by:tactic->refinement) =
802 fun tac ((mvs,inst),gls,just) ->
803 if gls = [] then failwith "No goal set" else
806 let ((newmvs,newinst),subgls,subjust) = tac g in
807 let n = length subgls in
808 let mvs' = union newmvs mvs
809 and inst' = compose_insts inst newinst
810 and gls' = subgls @ map (inst_goal newinst) ogls in
812 let i' = compose_insts inst' i in
813 let cths,oths = chop_list n ths in
814 let sths = (subjust i cths) :: oths in
816 (mvs',inst'),gls',just';;
818 (* ------------------------------------------------------------------------- *)
819 (* Rotate the goalstate either way. *)
820 (* ------------------------------------------------------------------------- *)
822 let (rotate:int->refinement) =
823 let rotate_p (meta,sgs,just) =
824 let sgs' = (tl sgs)@[hd sgs] in
826 let ths' = (last ths)::(butlast ths) in
829 and rotate_n (meta,sgs,just) =
830 let sgs' = (last sgs)::(butlast sgs) in
832 let ths' = (tl ths)@[hd ths] in
835 fun n -> if n > 0 then funpow n rotate_p
836 else funpow (-n) rotate_n;;
838 (* ------------------------------------------------------------------------- *)
839 (* Perform refinement proof, tactic proof etc. *)
840 (* ------------------------------------------------------------------------- *)
842 let (mk_goalstate:goal->goalstate) =
844 if type_of w = bool_ty then
846 (fun inst [th] -> INSTANTIATE_ALL inst th)
847 else failwith "mk_goalstate: Non-boolean goal";;
849 let (TAC_PROOF : goal * tactic -> thm) =
851 let gstate = mk_goalstate g in
852 let _,sgs,just = by tac gstate in
853 if sgs = [] then just null_inst []
854 else failwith "TAC_PROOF: Unsolved goals";;
857 let th = TAC_PROOF(([],t),tac) in
859 if t' = t then th else
860 try EQ_MP (ALPHA t' t) th
861 with Failure _ -> failwith "prove: justification generated wrong theorem";;
863 (* ------------------------------------------------------------------------- *)
864 (* Interactive "subgoal package" stuff. *)
865 (* ------------------------------------------------------------------------- *)
867 let current_goalstack = ref ([] :goalstack);;
869 let (refine:refinement->goalstack) =
871 let l = !current_goalstack in
872 if l = [] then failwith "No current goal" else
874 let res = r h :: l in
875 current_goalstack := res;
878 let flush_goalstack() =
879 let l = !current_goalstack in
880 current_goalstack := [hd l];;
882 let e tac = refine(by(VALID tac));;
884 let r n = refine(rotate n);;
886 let set_goal(asl,w) =
888 [mk_goalstate(map (fun t -> "",ASSUME t) asl,w)];
892 let fvs = sort (<) (map (fst o dest_var) (frees t)) in
894 let errmsg = end_itlist (fun s t -> s^", "^t) fvs in
895 warn true ("Free variables in goal: "^errmsg)
900 let l = !current_goalstack in
901 if length l = 1 then failwith "Can't back up any more" else
902 current_goalstack := tl l;
909 let (_,((asl,w)::_),_)::_ = !current_goalstack in
913 let asl,w = top_realgoal() in
914 map (concl o snd) asl,w;;
917 let (_,[],f)::_ = !current_goalstack in
920 (* ------------------------------------------------------------------------- *)
921 (* Install the goal-related printers. *)
922 (* ------------------------------------------------------------------------- *)
924 #install_printer print_goal;;
925 #install_printer print_goalstack;;