1(* ========================================================================= *) 2(* *) 3(* Inductive Definitions (John Harrison) *) 4(* *) 5(* ========================================================================= *) 6 7structure InductiveDefinition :> InductiveDefinition = 8struct 9 10open HolKernel boolLib liteLib refuteLib AC Ho_Rewrite; 11 12(* Fix the grammar used by this file *) 13structure Parse = 14struct 15 open Parse 16 val (Type,Term) = Parse.parse_from_grammars boolTheory.bool_grammars 17 fun == q x = Type q 18end 19open Parse 20 21(*--------------------------------------------------------------------------- 22 Variants. We re-define the kernel "variant" function here because 23 of a subtle difference between Hol98 variant and Hol88/light 24 variant functions: the former only looks at strings, while the 25 latter look at variables. For example 26 27 variant [`x:bool`] `x:'a` 28 29 yields x' in Hol98, but `x` in the latter (I think). The following 30 version of variant also does not vary away from constants with the 31 same name, maybe it should. 32 ---------------------------------------------------------------------------*) 33 34local fun prime v = let val (n,ty) = dest_var v in mk_var(n^"'",ty) end 35in 36fun vary V v = if op_mem aconv v V then vary V (prime v) else v 37end 38 39(* ------------------------------------------------------------------------- *) 40(* Produces a sequence of variants, considering previous inventions. *) 41(* ------------------------------------------------------------------------- *) 42 43fun variants av [] = [] 44 | variants av (h::t) = 45 let val vh = vary av h 46 in vh::variants (vh::av) t 47 end; 48 49(* ------------------------------------------------------------------------- *) 50(* Apply a destructor as many times as elements in list. *) 51(* ------------------------------------------------------------------------- *) 52 53fun nsplit dest clist x = 54 if null clist then ([],x) else 55 let val (l,r) = dest x 56 val (ll,y) = nsplit dest (tl clist) r 57 in (l::ll,y) 58 end;; 59 60(* ------------------------------------------------------------------------- *) 61(* Strip off exactly n arguments from combination. *) 62(* ------------------------------------------------------------------------- *) 63 64val strip_ncomb = 65 let fun strip(n,tm,acc) = 66 if n < 1 then (tm,acc) else 67 let val (l,r) = dest_comb tm 68 in strip(n - 1,l,r::acc) 69 end 70 in fn n => fn tm => strip(n,tm,[]) 71 end;; 72 73(* ------------------------------------------------------------------------- *) 74(* Share out list according to pattern in list-of-lists. *) 75(* ------------------------------------------------------------------------- *) 76 77fun shareout [] _ = [] 78 | shareout (h::t) all = 79 let val (l,r) = split_after (length h) all 80 in l::shareout t r 81 end; 82 83(* ------------------------------------------------------------------------- *) 84(* Produce a set of reasonably readable arguments, using variants if needed. *) 85(* ------------------------------------------------------------------------- *) 86 87val make_args = 88 let fun margs n avoid tys = 89 if null tys then [] else 90 let val v = variant avoid (mk_var("a"^(int_to_string n),hd tys)) 91 in v::margs (n + 1) (v::avoid) (tl tys) 92 end 93 in margs 0 end;; 94 95(* ------------------------------------------------------------------------- *) 96(* Grabs conclusion of rule, whether or not it has an antecedant. *) 97(* ------------------------------------------------------------------------- *) 98 99fun getconcl tm = 100 let val bod = repeat (snd o dest_forall) tm 101 in snd(dest_imp bod) handle HOL_ERR _ => bod 102 end;; 103 104(* ------------------------------------------------------------------------- *) 105(* Likewise, but quantify afterwards. *) 106(* ------------------------------------------------------------------------- *) 107 108fun HALF_BETA_EXPAND args th = GENL args (RIGHT_BETAS args th);; 109 110(* ------------------------------------------------------------------------- *) 111(* Converse of SIMPLE_DISJ_CASES, i.e. P \/ Q |- R => P |- R, Q |- R *) 112(* ------------------------------------------------------------------------- *) 113 114fun SIMPLE_DISJ_PAIR th = 115 let val (l,r) = dest_disj(hd(hyp th)) 116 in (PROVE_HYP (DISJ1 (ASSUME l) r) th,PROVE_HYP (DISJ2 l (ASSUME r)) th) 117 end;; 118 119(* ------------------------------------------------------------------------- *) 120(* Iterated FORALL_IMP_CONV: (!x1..xn. P[xs] ==> Q) => (?x1..xn. P[xs]) ==> Q*) 121(* ------------------------------------------------------------------------- *) 122 123val lhand = rand o rator;; 124 125fun FORALL_IMPS_CONV tm = 126 let val (avs,bod) = strip_forall tm 127 val th1 = DISCH tm (UNDISCH(SPEC_ALL(ASSUME tm))) 128 val th2 = itlist SIMPLE_CHOOSE avs th1 129 val tm2 = hd(hyp th2) 130 val th3 = DISCH tm2 (UNDISCH th2) 131 val th4 = ASSUME (concl th3) 132 val ant = lhand bod 133 val th5 = itlist SIMPLE_EXISTS avs (ASSUME ant) 134 val th6 = GENL avs (DISCH ant (MP th4 th5)) 135 in IMP_ANTISYM_RULE (DISCH_ALL th3) (DISCH_ALL th6) end;; 136 137(* ------------------------------------------------------------------------- *) 138(* (!x1..xn. P1[xs] ==> Q[xs]) /\ ... /\ (!x1..xn. Pm[xs] ==> Q[xs]) *) 139(* => (!x1..xn. P1[xs] \/ ... \/ Pm[xs] ==> Q[xs]) *) 140(* ------------------------------------------------------------------------- *) 141 142fun AND_IMPS_CONV tm = 143 let val ths = CONJUNCTS(ASSUME tm) 144 val avs = fst(strip_forall(concl(hd ths))) 145 val thl = map (DISCH tm o UNDISCH o SPEC_ALL) ths 146 val th1 = end_itlist SIMPLE_DISJ_CASES thl 147 val tm1 = hd(hyp th1) 148 val th2 = GENL avs (DISCH tm1 (UNDISCH th1)) 149 val tm2 = concl th2 150 val th3 = DISCH tm2 (UNDISCH (SPEC_ALL (ASSUME tm2))) 151 val (thts,tht) = nsplit SIMPLE_DISJ_PAIR (tl ths) th3 152 fun proc_fn th = 153 let val t = hd(hyp th) in GENL avs (DISCH t (UNDISCH th)) 154 end 155 val th4 = itlist (CONJ o proc_fn) thts (proc_fn tht) 156 in IMP_ANTISYM_RULE (DISCH_ALL th2) (DISCH_ALL th4) end;; 157 158(* ------------------------------------------------------------------------- *) 159(* A, x = t |- P[x] *) 160(* ------------------ EXISTS_EQUATION *) 161(* A |- ?x. P[x] *) 162(* ------------------------------------------------------------------------- *) 163 164val EXISTS_EQUATION = Prim_rec.EXISTS_EQUATION 165 166(* ========================================================================= *) 167(* Part 1: The main part of the inductive definitions package. *) 168(* ========================================================================= *) 169 170(* ------------------------------------------------------------------------- *) 171(* Translates a single clause to have variable arguments, simplifying. *) 172(* ------------------------------------------------------------------------- *) 173 174(* ------------------------------------------------------------------------- *) 175(* [JRH] Removed "Fail" constructor from handle trap. *) 176(* ------------------------------------------------------------------------- *) 177 178local 179 fun redres_eq {redex=x1,residue=e1} {redex=x2,residue=e2} = 180 aconv x1 x2 andalso aconv e1 e2 181 fun getequs(avs,[]) = [] 182 | getequs(avs,(h as {redex=r,residue})::t) = 183 if op_mem aconv r avs then 184 h::getequs(avs,filter (fn{redex,...} => not(aconv r redex)) t) 185 else getequs(avs,t) 186 fun calculate_simp_sequence avs plis = 187 let val oks = getequs(avs,plis) 188 in (oks,op_set_diff redres_eq plis oks) 189 end 190 fun mk_eq_of_bind{redex,residue} = mk_eq(residue,redex) 191in 192fun canonicalize_clause clause carg = 193 let val (avs,bimp) = strip_forall clause 194 val (ant,con) = dest_imp bimp handle HOL_ERR _ => (T,bimp) 195 val (rel,xargs) = strip_comb con 196 val plis = map2 (curry op |->) xargs carg 197 val (yes,no) = calculate_simp_sequence avs plis 198 val nvs = filter (not o C (op_mem aconv) (map #redex yes)) avs 199 val eth = 200 if is_imp bimp then 201 let val atm = itlist (curry mk_conj o mk_eq_of_bind) (yes@no) ant 202 val (ths,tth) = nsplit CONJ_PAIR plis (ASSUME atm) 203 val thl = map 204 (fn t => first(fn th => aconv (lhs(concl th)) t) ths) 205 carg 206 val th0 = MP (SPECL avs (ASSUME clause)) tth 207 val th1 = rev_itlist (C (curry MK_COMB)) thl (REFL rel) 208 val th2 = EQ_MP (SYM th1) th0 209 val th3 = INST yes (DISCH atm th2) 210 val tm4 = funpow (length yes) rand (lhand(concl th3)) 211 val th4 = itlist (CONJ o REFL o #residue) yes (ASSUME tm4) 212 val th5 = GENL carg (GENL nvs (DISCH tm4 (MP th3 th4))) 213 val th6 = SPECL nvs (SPECL (map #redex plis) (ASSUME(concl th5))) 214 val th7 = itlist (CONJ o REFL o #redex) no (ASSUME ant) 215 val th8 = GENL avs (DISCH ant (MP th6 th7)) 216 in IMP_ANTISYM_RULE (DISCH_ALL th5) (DISCH_ALL th8) 217 end 218 else 219 let val _ = not (null no) orelse 220 raise mk_HOL_ERR "InductiveDefinition" 221 "canonicalize_clause" 222 "Vacuous clause trivialises whole definition" 223 val atm = list_mk_conj(map mk_eq_of_bind (yes@no)) 224 val ths = CONJUNCTS (ASSUME atm) 225 val thl = map 226 (fn t => first(fn th => aconv (lhs(concl th)) t) ths) 227 carg 228 val th0 = SPECL avs (ASSUME clause) 229 val th1 = rev_itlist (C (curry MK_COMB)) thl (REFL rel) 230 val th2 = EQ_MP (SYM th1) th0 231 val th3 = INST yes (DISCH atm th2) 232 val tm4 = funpow (length yes) rand (lhand(concl th3)) 233 val th4 = itlist (CONJ o REFL o #residue) yes (ASSUME tm4) 234 val th5 = GENL carg (GENL nvs (DISCH tm4 (MP th3 th4))) 235 val th6 = SPECL nvs (SPECL (map #redex plis) (ASSUME(concl th5))) 236 val th7 = end_itlist CONJ (map (REFL o #redex) no) 237 val th8 = GENL avs (MP th6 th7) 238 in IMP_ANTISYM_RULE (DISCH_ALL th5) (DISCH_ALL th8) 239 end 240 val ftm = funpow (length carg) (body o rand) (rand(concl eth)) 241 in TRANS eth (itlist MK_FORALL carg (FORALL_IMPS_CONV ftm)) 242 end 243 handle e => raise (wrap_exn "InductiveDefinition" "canonicalize_clause" e) 244end; 245 246(* ------------------------------------------------------------------------- *) 247(* Canonicalizes the set of clauses, disjoining compatible antecedants. *) 248(* ------------------------------------------------------------------------- *) 249 250local fun assoc2 x (h1::t1,h2::t2) = if aconv x h1 then h2 else assoc2 x (t1,t2) 251 | assoc2 x _ = fail() 252in 253fun canonicalize_clauses clauses = 254 let val concls = map getconcl clauses 255 val uncs = map strip_comb concls 256 val rels = itlist (op_insert aconv o fst) uncs [] 257 val xargs = map (C (op_assoc aconv) uncs) rels 258 val closed = list_mk_conj clauses 259 val avoids = all_vars closed 260 val flargs = make_args avoids (map type_of (end_foldr (op @) xargs)) 261 val vargs = shareout xargs flargs 262 val cargs = map (C assoc2 (rels,vargs) o fst) uncs 263 val cthms = map2 canonicalize_clause clauses cargs 264 val pclauses = map (rand o concl) cthms 265 fun collectclauses tm = 266 mapfilter (fn t => if aconv (fst t) tm then snd t else fail()) 267 (zip (map fst uncs) pclauses) 268 val clausell = map collectclauses rels 269 val cclausel = map list_mk_conj clausell 270 val cclauses = list_mk_conj cclausel 271 and oclauses = list_mk_conj pclauses 272 val pth = TRANS (end_itlist MK_CONJ cthms) 273 (CONJ_ACI(mk_eq(oclauses,cclauses))) 274 in TRANS pth (end_itlist MK_CONJ (map AND_IMPS_CONV cclausel)) 275 end 276 handle e => raise (wrap_exn "InductiveDefinition" "canonicalize_clauses" e) 277end; 278 279 280(* ------------------------------------------------------------------------- *) 281(* Prove definitions work for non-schematic relations with canonical rules. *) 282(* ------------------------------------------------------------------------- *) 283 284fun derive_canon_inductive_relations pclauses = 285 let val closed = list_mk_conj pclauses 286 val pclauses = strip_conj closed 287 val (vargs,bodies) = split(map strip_forall pclauses) 288 val (ants,concs) = split(map dest_imp bodies) 289 val rels = map (repeat rator) concs 290 val avoids = all_vars closed 291 val rels' = variants avoids rels 292 val prime_fn = subst (map2 (curry op |->) rels rels' ) 293 val closed' = prime_fn closed 294 fun mk_def arg con = 295 mk_eq(repeat rator con, 296 list_mk_abs(arg,list_mk_forall(rels', 297 mk_imp(closed',prime_fn con)))) 298 val deftms = map2 mk_def vargs concs 299 val defthms = map2 HALF_BETA_EXPAND vargs (map ASSUME deftms) 300 fun mk_ind args th = 301 let val th1 = fst(EQ_IMP_RULE(SPEC_ALL th)) 302 val ant = lhand(concl th1) 303 val th2 = SPECL rels' (UNDISCH th1) 304 in GENL args (DISCH ant (UNDISCH th2)) 305 end 306 val indthms = map2 mk_ind vargs defthms 307 val indthmr = end_itlist CONJ indthms 308 val indthm = GENL rels' (DISCH closed' indthmr) 309 val mconcs = map2 (fn a => fn t => 310 list_mk_forall(a,mk_imp(t,prime_fn t))) vargs ants 311 val monotm = mk_imp(concl indthmr,list_mk_conj mconcs) 312 val monothm = ASSUME(list_mk_forall(rels,list_mk_forall(rels',monotm))) 313 val closthm = ASSUME closed' 314 val monothms = CONJUNCTS 315 (MP (SPEC_ALL monothm) (MP (SPECL rels' indthm) closthm)) 316 val closthms = CONJUNCTS closthm 317 fun prove_rule mth (cth,dth) = 318 let val (avs,bod) = strip_forall(concl mth) 319 val th1 = IMP_TRANS (SPECL avs mth) (SPECL avs cth) 320 val th2 = GENL rels' (DISCH closed' (UNDISCH th1)) 321 val th3 = EQ_MP (SYM (SPECL avs dth)) th2 322 in GENL avs (DISCH (lhand bod) th3) 323 end 324 val ruvalhms = map2 prove_rule monothms (zip closthms defthms) 325 val ruvalhm = end_itlist CONJ ruvalhms 326 val dtms = map2 (curry list_mk_abs) vargs ants 327 val double_fn = subst (map2 (curry op |->) rels dtms) 328 fun mk_unbetas tm dtm = 329 let val (avs,bod) = strip_forall tm 330 val (il,r) = dest_comb bod 331 val (i,l) = dest_comb il 332 val bth = RIGHT_BETAS avs (REFL dtm) 333 val munb = AP_THM (AP_TERM i bth) r 334 val iunb = AP_TERM (mk_comb(i,double_fn l)) bth 335 val junb = AP_TERM (mk_comb(i,r)) bth 336 val quantify = itlist MK_FORALL avs 337 in (quantify munb,(quantify iunb,quantify junb)) 338 end 339 val unths = map2 mk_unbetas pclauses dtms 340 val irthm = EQ_MP (SYM(end_itlist MK_CONJ (map fst unths))) ruvalhm 341 val mrthm = MP (SPECL rels (SPECL dtms monothm)) irthm 342 val imrth = EQ_MP 343 (SYM(end_itlist MK_CONJ (map (fst o snd) unths))) mrthm 344 val ifthm = MP (SPECL dtms indthm) imrth 345 val fthm = EQ_MP (end_itlist MK_CONJ (map (snd o snd) unths)) ifthm 346 fun mk_case th1 th2 = 347 let val avs = fst(strip_forall(concl th1)) 348 in GENL avs (IMP_ANTISYM_RULE (SPEC_ALL th1) (SPEC_ALL th2)) 349 end 350 val casethm = end_itlist CONJ 351 (map2 mk_case (CONJUNCTS fthm) (CONJUNCTS ruvalhm)) 352 in CONJ ruvalhm (CONJ indthm casethm) 353 end 354 handle e => raise (wrap_exn "InductiveDefinition" 355 "derive_canon_inductive_relations"e); 356 357(* ------------------------------------------------------------------------- *) 358(* General case for nonschematic relations; monotonicity & defn hyps. *) 359(* ------------------------------------------------------------------------- *) 360 361fun derive_nonschematic_inductive_relations tm = 362 let val clauses = strip_conj tm 363 val canonthm = canonicalize_clauses clauses 364 val canonthm' = SYM canonthm 365 val pclosed = rand(concl canonthm) 366 val pclauses = strip_conj pclosed 367 val rawthm = derive_canon_inductive_relations pclauses 368 val (ruvalhm,otherthms) = CONJ_PAIR rawthm 369 val (indthm,casethm) = CONJ_PAIR otherthms 370 val ruvalhm' = EQ_MP canonthm' ruvalhm 371 and indthm' = CONV_RULE (ONCE_DEPTH_CONV (REWR_CONV canonthm')) indthm 372 in CONJ ruvalhm' (CONJ indthm' casethm) 373 end 374 handle e => raise (wrap_exn "InductiveDefinition" 375 "derive_nonschematic_inductive_relations" e); 376 377 378(* ========================================================================= *) 379(* Part 2: Tactic-integrated tools for proving monotonicity automatically. *) 380(* ========================================================================= *) 381 382 383(* ---------------------------------------------------------------------- 384 MONO_ABS_TAC 385 386 ?- (\x. P[x]) x1 .. xn ==> (\y. Q[y]) x1 .. xn 387 ================================================== 388 ?- P[x1] x2 .. xn ==> Q[x1] x2 .. xn 389 390 ---------------------------------------------------------------------- *) 391 392fun MONO_ABS_TAC (asl,w) = 393 let val (ant,con) = dest_imp w 394 val vars = snd(strip_comb con) 395 val rnum = length vars - 1 396 val (hd1,args1) = strip_ncomb rnum ant 397 and (hd2,args2) = strip_ncomb rnum con 398 val th1 = rev_itlist (C AP_THM) args1 (BETA_CONV hd1) 399 and th2 = rev_itlist (C AP_THM) args1 (BETA_CONV hd2) 400 val th3 = MK_COMB(AP_TERM boolSyntax.implication th1,th2) 401 in CONV_TAC(REWR_CONV th3) (asl,w) 402 end;; 403 404(* ---------------------------------------------------------------------- 405 MONO_UNCURRY_TAC 406 407 ?- UNCURRY f x1 .. xn ==> UNCURRY f' x1 .. xn 408 ================================================== 409 ?- f y1 y2 .. xn ==> f' y1 y2 .. xn 410 411 ---------------------------------------------------------------------- *) 412 413fun MONO_UNCURRY_TAC (asl, w) = let 414 val U = DB.fetch "pair" "UNCURRY" 415 val (ant, con) = dest_imp w 416 val vars = snd (strip_comb con) 417 val rnum = length vars - 2 418 val (hd1, args1) = strip_ncomb rnum ant 419 val (hd2, args2) = strip_ncomb rnum con 420 val th1 = rev_itlist (C AP_THM) args1 (ISPECL (#2 (strip_comb hd1)) U) 421 val th2 = rev_itlist (C AP_THM) args2 (ISPECL (#2 (strip_comb hd2)) U) 422 val th3 = MK_COMB(AP_TERM boolSyntax.implication th1, th2) 423in 424 CONV_TAC (REWR_CONV th3) (asl, w) 425end 426 427 428(* ------------------------------------------------------------------------- *) 429(* Collection, so users can add their own rules. *) 430(* *) 431(* As a simple speedup, the tactics are indexed by head operator in the *) 432(* relevant expression. If there isn't a head constant, use the empty string.*) 433(* ------------------------------------------------------------------------- *) 434(* ------------------------------------------------------------------------- *) 435(* Simplified version of MATCH_MP_TAC to avoid quantifier troubles. *) 436(* ------------------------------------------------------------------------- *) 437 438fun BACKCHAIN_TAC th = 439 let val match_fn = HO_PART_MATCH (snd o dest_imp) th 440 in fn (asl,w) => 441 let val th1 = match_fn w 442 val (ant,con) = dest_imp(concl th1) 443 in ([(asl,ant)],fn [t] => HO_MATCH_MP th1 t | _ => raise Match) 444 end 445 end;; 446 447type monoset = (string * thm) list; 448 449(*--------------------------------------------------------------------------- 450 * MONO_AND = |- (A ==> B) /\ (C ==> D) ==> (A /\ C ==> B /\ D) 451 * MONO_OR = |- (A ==> B) /\ (C ==> D) ==> (A \/ C ==> B \/ D) 452 * MONO_IMP = |- (B ==> A) /\ (C ==> D) ==> ((A ==> C) ==> (B ==> D)) 453 * MONO_NOT = |- (B ==> A) ==> (~A ==> ~B) 454 * MONO_COND = |- (w ==> x) /\ (y ==> z) ==> (COND b w y) ==> (COND b x z) 455 * MONO_ALL = |- (!x. P x ==> Q x) ==> ((!x. P x) ==> (!x. Q x)) 456 * MONO_EXISTS = |- (!x. P x ==> Q x) ==> ((?x. P x) ==> (?x. Q x)) 457 *---------------------------------------------------------------------------*) 458 459 460val MONO_EXISTS = prove ( 461 ``(!x:'a. P x ==> Q x) ==> ($? P ==> $? Q)``, 462 DISCH_THEN(MP_TAC o HO_MATCH_MP MONO_EXISTS) THEN 463 CONV_TAC(ONCE_DEPTH_CONV ETA_CONV) THEN REWRITE_TAC[]) 464 465val MONO_FORALL = prove ( 466 ``(!x:'a. P x ==> Q x) ==> ($! P ==> $! Q)``, 467 DISCH_THEN(MP_TAC o HO_MATCH_MP MONO_ALL) THEN 468 CONV_TAC(ONCE_DEPTH_CONV ETA_CONV) THEN REWRITE_TAC[]) 469 470val MONO_RESFORALL = prove( 471 ``(!x:'a. P' x ==> P x) /\ (!x. Q x ==> Q' x) ==> 472 (RES_FORALL P Q ==> RES_FORALL P' Q')``, 473 REWRITE_TAC [RES_FORALL_THM, IN_DEF] THEN BETA_TAC THEN REPEAT STRIP_TAC THEN 474 REPEAT (FIRST_X_ASSUM MATCH_MP_TAC) THEN ASM_REWRITE_TAC []) 475 476val MONO_RESEXISTS = prove( 477 ``(!x:'a. P x ==> P' x) /\ (!x. Q x ==> Q' x) ==> 478 (RES_EXISTS P Q ==> RES_EXISTS P' Q')``, 479 REWRITE_TAC [RES_EXISTS_THM, IN_DEF] THEN BETA_TAC THEN REPEAT STRIP_TAC THEN 480 EXISTS_TAC ``x:'a`` THEN RES_TAC THEN ASM_REWRITE_TAC []) 481 482val MONO_COND = let open Rewrite boolTheory in 483 ONCE_REWRITE_RULE[AND_IMP_INTRO]MONO_COND 484end 485 486val bool_monoset = 487 [("/\\", MONO_AND), 488 ("\\/", MONO_OR), 489 ("?", MONO_EXISTS), 490 ("!", MONO_FORALL), 491 ("==>", MONO_IMP), 492 ("~", MONO_NOT), 493 ("COND",MONO_COND), 494 ("RES_FORALL", MONO_RESFORALL), 495 ("RES_EXISTS", MONO_RESEXISTS)] 496 497 498val IMP_REFL = let val p = mk_var("p", bool) in ASSUME p |> DISCH p |> GEN p end 499 500fun APPLY_MONOTAC monoset (asl, w) = let 501 val (a,c) = dest_imp w 502in 503 if aconv a c then ACCEPT_TAC (SPEC a IMP_REFL) (asl,w) 504 else let 505 val {Thy,Name,...} = dest_thy_const(repeat rator c) 506 handle HOL_ERR _ => {Thy = "", Name = "", 507 Ty = Type.alpha} 508 in 509 case (Thy,Name) of 510 ("","") => MONO_ABS_TAC (asl, w) 511 | ("pair", "UNCURRY") => MONO_UNCURRY_TAC (asl, w) 512 | _ => tryfind (fn (k,t) => if k = Name then BACKCHAIN_TAC t (asl,w) 513 else fail()) 514 monoset 515 end 516end 517 518(* ------------------------------------------------------------------------- *) 519(* Tactics to prove monotonicity automatically. *) 520(* ------------------------------------------------------------------------- *) 521 522fun MONO_STEP_TAC finisher monoset = 523 REPEAT (GEN_TAC ORELSE CONJ_TAC) THEN 524 (APPLY_MONOTAC monoset ORELSE finisher) 525 526fun MONO_TAC monoset = let 527 (* first case is for monotonicity proving in making the definition, where 528 there will be an assumption of the form 529 !vs. P vs ==> P' vs 530 to hand. 531 The second case (after the ORELSE) is for proving strong induction, where 532 there won't be any assumptions, but the goal will have reduced to 533 con vs /\ con' vs ==> con vs 534 *) 535 val finisher = FIRST_ASSUM MATCH_ACCEPT_TAC ORELSE 536 (REPEAT STRIP_TAC THEN FIRST_ASSUM ACCEPT_TAC) 537in 538 REPEAT (MONO_STEP_TAC finisher monoset) 539end 540 541(* =========================================================================*) 542(* Part 3: Utility functions to modify the basic theorems in various ways. *) 543(* *) 544(* There are various fnctions that can be applied to a theorem: *) 545(* *) 546(* (1) Attempt to prove the monotonicity hypotheses *) 547(* *) 548(* (2) Generalize it over schematic variables *) 549(* *) 550(* (3) Derive a raw existence assertion *) 551(* *) 552(* (4) Actually make definitions of the inductive relations. *) 553(* *) 554(* Generally one applies either or both of (1) and (2), then does (4). *) 555(* =========================================================================*) 556 557(* ------------------------------------------------------------------------- *) 558(* Attempt to dispose of the non-equational assumption(s) of a theorem. *) 559(* ------------------------------------------------------------------------- *) 560 561fun prove_monotonicity_hyps monoset = 562 let val tac = REPEAT GEN_TAC THEN 563 DISCH_THEN(REPEAT_TCL CONJUNCTS_THEN ASSUME_TAC) THEN 564 REPEAT CONJ_TAC THEN (MONO_TAC monoset) 565 fun prove_mth t = TAC_PROOF(([],t),tac) 566 in fn th => 567 let val mths = mapfilter prove_mth (filter (not o is_eq) (hyp th)) 568 in itlist PROVE_HYP mths th 569 end 570 end 571 handle e => raise (wrap_exn "InductiveDefinition" 572 "prove_monotonicity_hyps" e); 573 574(* ------------------------------------------------------------------------- *) 575(* Generalize definitions and theorem over given variables (all the same!) *) 576(* ------------------------------------------------------------------------- *) 577 578fun generalize_schematic_variables vs = 579 let fun generalize_def tm th = 580 let val (l,r) = dest_eq tm 581 val (lname,lty) = dest_var l 582 val l' = mk_var(lname,itlist (curry (op -->) o type_of) vs lty) 583 val r' = list_mk_abs(vs,r) 584 val tm' = mk_eq(l',r') 585 val th0 = RIGHT_BETAS vs (ASSUME tm') 586 val th1 = INST [l |-> lhs(concl th0)] (DISCH tm th) 587 in MP th1 th0 588 end 589 in fn th => 590 let val (defs,others) = partition is_eq (hyp th) 591 val others' = 592 map (fn t => let val fvs = free_vars t 593 in SPECL fvs (ASSUME (list_mk_forall(fvs,t))) 594 end) 595 others 596 val th1 = itlist generalize_def defs th 597 in GENL vs (itlist PROVE_HYP others' th1) 598 end 599 end; 600 601(* ------------------------------------------------------------------------- *) 602(* Derive existence. *) 603(* ------------------------------------------------------------------------- *) 604 605fun derive_existence th = itlist EXISTS_EQUATION (filter is_eq (hyp th)) th 606 607(* ------------------------------------------------------------------------- *) 608(* Make definitions. *) 609(* ------------------------------------------------------------------------- *) 610 611fun make_definitions stem th = let 612 val defs = filter is_eq (hyp th) 613 fun mkdef i tm = 614 new_definition(stem ^ Int.toString i ^ !boolLib.def_suffix, tm) 615 val dths = if length defs = 1 then 616 [new_definition(stem ^ !boolLib.def_suffix, hd defs)] 617 else 618 mapi mkdef defs 619 val insts = map2 (curry op |->) (map lhs defs) (map (lhs o concl) dths) 620in 621 rev_itlist (C MP) dths (INST insts (itlist DISCH defs th)) 622end 623 624(* ------------------------------------------------------------------------- *) 625(* "Unschematize" a set of clauses. *) 626(* ------------------------------------------------------------------------- *) 627 628val inddef_strict = ref false; 629val _ = Feedback.register_btrace ("inddef strict", inddef_strict); 630 631fun indented_term_to_string n tm = let 632 val nspaces = CharVector.tabulate(n, K #" ") 633 fun pper tm = let 634 open smpp 635 in 636 add_string nspaces >> 637 block PP.CONSISTENT n ( 638 Lib.with_flag (Parse.current_backend, PPBackEnd.raw_terminal) 639 (lift Parse.pp_term) 640 tm 641 ) 642 end 643in 644 PP.pp_to_string (!Globals.linewidth) (Parse.mlower o pper) tm 645end 646 647 648local 649 fun pare_comb qvs tm = 650 if null (op_intersect aconv (free_vars tm) qvs) 651 andalso all is_var (snd(strip_comb tm)) 652 then tm 653 else pare_comb qvs (rator tm) 654 fun schem_head cls = 655 let val (avs,bod) = strip_forall cls 656 in pare_comb avs (snd(dest_imp bod) handle HOL_ERR _ => bod) 657 end 658 fun common_prefix0 acc l1 l2 = 659 case (l1, l2) of 660 ([], _) => acc 661 | (_, []) => acc 662 | (h1::t1, h2::t2) => if aconv h1 h2 then common_prefix0 (h1::acc) t1 t2 663 else acc 664 fun common_prefix l1 l2 = List.rev (common_prefix0 [] l1 l2) 665 fun lcommon_prefix0 acc l = 666 case l of 667 [] => acc 668 | (h::t) => let 669 val newprefix = common_prefix acc h 670 in 671 if null newprefix then [] 672 else lcommon_prefix0 newprefix t 673 end 674 fun lcommon_prefix [] = [] 675 | lcommon_prefix (h::t) = lcommon_prefix0 h t 676 677in 678fun unschematize_clauses clauses = let 679 val schem = map schem_head clauses 680 val schems = op_mk_set aconv schem 681 fun insert_list l s = foldl (fn (t,s) => HOLset.add(s,t)) s l 682 val hdops = op_mk_set aconv (map (#1 o strip_comb) schems) 683 val schemv_extent = length (#2 (strip_comb (hd schems))) 684 fun is_hdop_instance t = let 685 val (f,args) = strip_comb t 686 in 687 op_mem aconv f hdops andalso length args = schemv_extent 688 end 689 val all_instances = 690 foldl (fn (t, s) => insert_list (find_terms is_hdop_instance t) s) 691 empty_tmset clauses 692 fun do_substitution schems = let 693 val avoids = all_vars (list_mk_conj clauses) 694 fun hack_fn tm = mk_var(fst(dest_var(repeat rator tm)),type_of tm) 695 val grels = variants avoids (map hack_fn schems) 696 val crels = map2 (curry op |->) schems grels 697 val clauses' = map (subst crels) clauses 698 in 699 (clauses',snd(strip_comb(hd schems))) 700 end 701in 702 if is_var(hd schem) then (clauses,[]) 703 else if !inddef_strict then 704 if not (HOLset.numItems all_instances = 1) then let 705 val instlist = HOLset.listItems all_instances 706 val t1_s = trace("types", 1) (indented_term_to_string 2) (hd instlist) 707 val t2_s = 708 trace("types", 1) (indented_term_to_string 2) (hd (tl instlist)) 709 in 710 failwith ("Schematic variable(s) not used consistently - witness\n"^ 711 t1_s^"\nand\n"^t2_s) 712 end 713 else 714 do_substitution schems 715 else (* liberal definitions *) let 716 val prefix_vars = HOLset.foldr (fn (t,l) => #2 (strip_comb t)::l) 717 [] all_instances 718 val prefix = lcommon_prefix prefix_vars 719 in 720 if null prefix then (clauses, []) 721 else let 722 val plist = String.concat (Lib.commafy 723 (map (quote o #1 o dest_var) prefix)) 724 val _ = HOL_MESG ("Treating "^plist^" as schematic variable"^ 725 (if length prefix > 1 then "s" else "")) 726 in 727 do_substitution (map (fn t => list_mk_comb(t, prefix)) hdops) 728 end 729 end 730 end 731end; 732 733(* ========================================================================= *) 734(* Part 4: The final user wrapper. *) 735(* ========================================================================= *) 736 737 738fun check_definition schemevars clocs tm = let 739 (* check that tm has no extra type variables or free variables other than *) 740 (* the heads of clauses *) 741 val clauses = strip_conj tm 742 fun ind_concl tm = #2 (dest_imp tm) handle HOL_ERR _ => tm 743 val relvars = 744 HOLset.addList(empty_tmset, 745 map (#1 o strip_comb o ind_concl o #2 o strip_forall) 746 clauses) 747 val okvars = foldl (fn (v,s) => HOLset.add(s,v)) relvars schemevars 748 val empty_tyset = HOLset.empty Type.compare 749 val reltyvars = HOLset.foldl (fn (tm,tyvset) => 750 HOLset.addList(tyvset, 751 type_vars_in_term tm)) 752 empty_tyset relvars 753 val reltyvars = List.foldl (fn (tm,tyvset) => 754 HOLset.addList(tyvset, 755 type_vars_in_term tm)) 756 reltyvars schemevars 757 758 (* check that there aren't duplicate names in the forall chain *) 759 fun check_clause_foralls n c = let 760 val (vs, body) = strip_forall c 761 val loc = List.nth(clocs, n) handle Subscript => locn.Loc_None 762 fun foldthis (v, acc) = let 763 val (nm, _) = dest_var v 764 in 765 if HOLset.member(acc, nm) then 766 raise mk_HOL_ERRloc "InductiveDefinition" 767 "check_clause" 768 loc 769 ("Clause #"^Int.toString (n + 1)^ 770 " contains duplicate name "^nm^ 771 " in outermost universal quantification") 772 else HOLset.add(acc, nm) 773 end 774 in 775 ignore (List.foldl foldthis (HOLset.empty String.compare) vs) 776 end 777 val _ = appi check_clause_foralls clauses 778 779 780 fun check_tyvars n c = let 781 val tyvs = HOLset.addList(empty_tyset, type_vars_in_term c) 782 in 783 if not (HOLset.isSubset(tyvs, reltyvars)) then let 784 val really_free = HOLset.difference(tyvs, reltyvars) 785 val free_list0 = HOLset.foldr (fn (v,sl) => dest_vartype v :: sl) 786 [] really_free 787 val free_list = Lib.commafy free_list0 788 val tmstring = trace ("types", 1) (indented_term_to_string 2) c 789 val loc = List.nth (clocs, n) handle Subscript => locn.Loc_None 790 in 791 raise mk_HOL_ERRloc 792 "InductiveDefinition" "check_clause" loc 793 (String.concat ("Clause #" :: Int.toString (n + 1):: 794 ":\n" :: tmstring :: 795 "\ncontains free type variable"^ 796 (if length free_list > 1 then "s" else "")^ 797 ": " :: free_list)) 798 end 799 else 800 () 801 end 802 val _ = appi check_tyvars clauses 803 804 805 806 (* here, generalise on the extra free variables if we're not being strict *) 807 fun check_clause n c = let 808 val fvs = FVL [c] empty_tmset 809 in 810 if not (HOLset.isSubset(fvs, okvars)) then let 811 val really_free = HOLset.difference(fvs, okvars) 812 val free_list0 = 813 HOLset.foldr (fn (v,sl) => Lib.quote (#1 (dest_var v)) :: sl) 814 [] really_free 815 val free_list = Lib.commafy free_list0 816 val loc = List.nth(clocs, n) handle Subscript => locn.Loc_None 817 in 818 if !inddef_strict then let 819 val tmstring = trace ("types", 1) (indented_term_to_string 2) c 820 in 821 raise mk_HOL_ERRloc 822 "InductiveDefinition" 823 "check_clause" 824 loc 825 (String.concat ("Clause #" :: Int.toString n :: 826 ",\n" :: tmstring :: 827 "\ncontains free variables: " :: 828 free_list)) 829 end 830 else 831 (HOL_MESG ("Generalising variable" ^ 832 (if length free_list > 1 then "s " else " ")^ 833 String.concat free_list ^ 834 " in clause #"^Int.toString n ^ 835 (if loc = locn.Loc_None then "" 836 else " ("^locn.toShortString loc^")")); 837 list_mk_forall (HOLset.listItems really_free, c)) 838 end 839 else c 840 end 841in 842 list_mk_conj (mapi check_clause clauses) 843end 844 845 846 847fun prove_nonschematic_inductive_relations_exist monoset tm = let 848 val th0 = derive_nonschematic_inductive_relations tm 849 val th1 = prove_monotonicity_hyps monoset th0 850in 851 derive_existence th1 852end 853 handle e => 854 raise (wrap_exn "InductiveDefinition" 855 "prove_nonschematic_inductive_relations_exist" e); 856 857(* ------------------------------------------------------------------------- *) 858(* The schematic case. *) 859(* *) 860(* All relations in a given call must have the same schematic args (if they *) 861(* aren't mutually inductive, use separate definitions), which must occur as *) 862(* the first arguments to each relation, in the same order(!) *) 863(* ------------------------------------------------------------------------- *) 864 865fun prove_inductive_relations_exist monoset tm = 866 let val clauses = strip_conj tm 867 val (clauses',fvs) = unschematize_clauses clauses 868 val th0 = derive_nonschematic_inductive_relations 869 (check_definition fvs [] (list_mk_conj clauses')) 870 val th1 = prove_monotonicity_hyps monoset th0 871 val th2 = generalize_schematic_variables fvs th1 872 in derive_existence th2 873 end 874 handle e => raise (wrap_exn "InductiveDefinition" 875 "prove_inductive_relations_exist" e); 876 877 878fun new_inductive_definition monoset stem (tm,clocs) = 879 let val clauses = strip_conj tm 880 val (clauses',fvs) = unschematize_clauses clauses 881 val th0 = derive_nonschematic_inductive_relations 882 (check_definition fvs clocs (list_mk_conj clauses')) 883 val th1 = prove_monotonicity_hyps monoset th0 884 val th2 = generalize_schematic_variables fvs th1 885 val th3 = make_definitions stem th2 886 val avs = fst(strip_forall(concl th3)) 887 val (r,ic) = CONJ_PAIR(SPECL avs th3) 888 val (i,c) = CONJ_PAIR ic 889 in (GENL avs r, GENL avs i, GENL avs c) 890 end 891 handle e => raise wrap_exn "InductiveDefinition" "new_inductive_definition" e; 892 893end (* InductiveDefinition *) 894