1structure markerLib :> markerLib = 2struct 3 4open HolKernel boolLib markerTheory markerSyntax; 5 6val ERR = mk_HOL_ERR "markerLib" ; 7 8(*---------------------------------------------------------------------------*) 9(* Support for "short-term markers". *) 10(*---------------------------------------------------------------------------*) 11 12val stmark_term = REWR_CONV (GSYM stmarker_def) 13 14fun stmark_conjunct P tm = let 15in 16 if is_conj tm then 17 LAND_CONV (stmark_conjunct P) ORELSEC RAND_CONV (stmark_conjunct P) 18 else if P tm then stmark_term 19 else NO_CONV 20end tm 21 22fun stmark_disjunct P tm = let 23in 24 if is_disj tm then 25 LAND_CONV (stmark_disjunct P) ORELSEC RAND_CONV (stmark_disjunct P) 26 else if P tm then stmark_term 27 else NO_CONV 28end tm 29 30fun is_stmarked t = same_const stmarker_tm (rator t) handle HOL_ERR _ => false 31 32val [comm, assoc, commassoc] = CONJUNCTS (SPEC_ALL markerTheory.move_left_conj) 33 34fun move_stmarked_conj_left tm = let 35in 36 if is_stmarked tm then ALL_CONV 37 else if is_conj tm then 38 (LAND_CONV move_stmarked_conj_left THENC TRY_CONV (REWR_CONV assoc)) 39 ORELSEC 40 (RAND_CONV move_stmarked_conj_left THENC 41 (REWR_CONV commassoc ORELSEC REWR_CONV comm)) 42 else NO_CONV 43end tm 44 45val move_stmarked_conj_left = 46 move_stmarked_conj_left THENC 47 (LAND_CONV (REWR_CONV stmarker_def) ORELSEC REWR_CONV stmarker_def) 48 49val move_stmarked_conj_right = 50 PURE_REWRITE_CONV [move_right_conj] THENC 51 (RAND_CONV (REWR_CONV stmarker_def) ORELSEC REWR_CONV stmarker_def) 52val move_stmarked_disj_left = 53 PURE_REWRITE_CONV [move_left_disj] THENC 54 (LAND_CONV (REWR_CONV stmarker_def) ORELSEC REWR_CONV stmarker_def) 55 56val move_stmarked_disj_right = 57 PURE_REWRITE_CONV [move_right_conj] THENC 58 (RAND_CONV (REWR_CONV stmarker_def) ORELSEC REWR_CONV stmarker_def) 59 60fun move_conj_left P = stmark_conjunct P THENC move_stmarked_conj_left 61fun move_conj_right P = stmark_conjunct P THENC move_stmarked_conj_right 62fun move_disj_left P = stmark_disjunct P THENC move_stmarked_disj_left 63fun move_disj_right P = stmark_disjunct P THENC move_stmarked_disj_right 64 65(*---------------------------------------------------------------------------*) 66(* Dealing with simplifier directives encoded as tags on theorems. *) 67(*---------------------------------------------------------------------------*) 68 69fun AC th1 th2 = 70 EQ_MP (SYM (SPECL [concl th1, concl th2] markerTheory.AC_DEF)) 71 (CONJ th1 th2); 72 73fun unAC th = let val th1 = PURE_REWRITE_RULE [AC_DEF] th 74 in (CONJUNCT1 th1, CONJUNCT2 th1) 75 end; 76 77fun Cong th = EQ_MP (SYM(SPEC (concl th) markerTheory.Cong_def)) th; 78 79fun unCong th = PURE_REWRITE_RULE [Cong_def] th; 80 81(*---------------------------------------------------------------------------*) 82(* Support for abbreviations. *) 83(*---------------------------------------------------------------------------*) 84 85val DeAbbrev = CONV_RULE (REWR_CONV Abbrev_def) 86 87fun Abbrev_wrap eqth = 88 EQ_MP (SYM (Thm.SPEC (concl eqth) Abbrev_def)) eqth 89 90fun ABB l r = 91 CHOOSE_THEN (fn th => SUBST_ALL_TAC th THEN ASSUME_TAC (Abbrev_wrap(SYM th))) 92 (Thm.EXISTS(mk_exists(l, mk_eq(r, l)), r) (Thm.REFL r)); 93 94fun ABBREV_TAC eq = let val (l,r) = dest_eq eq in ABB l r end; 95 96local 97 val match_var_or_const = ref true 98in 99 val () = Feedback.register_btrace 100 ("PAT_ABBREV_TAC: match var/const", match_var_or_const) 101 102 fun PAT_ABBREV_TAC fv_set eq (g as (asl, w)) = 103 let 104 open HOLset 105 val (l, r) = dest_eq eq 106 val rvs = FVL [r] empty_tmset 107 val l' = gen_variant Parse.is_constname "" 108 (listItems(union(fv_set, rvs))) l 109 fun matchr t = 110 case raw_match [] fv_set r t ([],[]) of 111 ((tmsub, _), (tysub, _)) => (tmsub, tysub) 112 fun finder (bvs, t) = 113 case List.find (fn v => HOLset.member(rvs, v)) bvs of 114 SOME _ => NONE 115 | NONE => 116 if (is_var t orelse is_const t) andalso not (!match_var_or_const) 117 then NONE 118 else 119 case Lib.total matchr t of 120 NONE => NONE 121 | SOME (tmsub, tysub) => 122 let 123 open HOLset 124 val bv_set = addList(empty_tmset, bvs) 125 fun badt t = 126 not (isEmpty (intersection (FVL [t] empty_tmset, 127 bv_set))) 128 in 129 case List.find (fn {redex,residue=t} => badt t) tmsub of 130 NONE => SOME(t, tysub) 131 | SOME _ => NONE 132 end 133 in 134 case gen_find_term finder w of 135 NONE => raise ERR "PAT_ABBREV_TAC" "No matching term found" 136 | SOME (t, tysub) => ABB (Term.inst tysub l') t g 137 end 138end 139 140fun fixed_tyvars ctxt pattern = 141 Lib.U (map type_vars_in_term (Lib.intersect ctxt (free_vars pattern))) 142 143fun ABB' {redex=l,residue=r} = ABB l r 144 145val safe_inst_cmp = let 146 fun img {redex,residue} = 147 (term_size residue, (residue, #1 (dest_var redex) handle HOL_ERR _ => "")) 148 val cmp = pair_compare 149 (flip_cmp Int.compare, pair_compare (Term.compare, String.compare)) 150in 151 inv_img_cmp img cmp 152end 153val safe_inst_sort = 154 List.filter 155 (fn {redex,residue} => String.sub(#1 (dest_var redex),0) <> #"_") o 156 Listsort.sort safe_inst_cmp 157 158fun MATCH_ABBREV_TAC fv_set pattern (g as (asl, w)) = let 159 val ctxt = HOLset.listItems fv_set 160 val (tminst,_) = match_terml (fixed_tyvars ctxt pattern) fv_set pattern w 161in 162 MAP_EVERY ABB' (safe_inst_sort tminst) g 163end 164 165fun MATCH_ASSUM_ABBREV_TAC fv_set pattern (g as (asl, w)) = let 166 val ctxt = HOLset.listItems fv_set 167 val fixed = fixed_tyvars ctxt pattern 168 fun find [] = raise ERR "MATCH_ASSUM_ABBREV_TAC" "No matching assumption found" 169 | find (asm::tl) = 170 case total (match_terml fixed fv_set pattern) asm of 171 NONE => find tl 172 | SOME (tminst,_) => MAP_EVERY ABB' (safe_inst_sort tminst) g 173 handle HOL_ERR e => find tl 174in find asl end 175 176fun HO_MATCH_ABBREV_TAC fv_set pattern (gl as (asl,w)) = 177 let val ctxt = HOLset.listItems fv_set 178 val (tminst, tyinst) = ho_match_term (fixed_tyvars ctxt pattern) fv_set pattern w 179 val unbeta_goal = 180 Tactical.default_prover(mk_eq(w, subst tminst (inst tyinst pattern)), 181 BETA_TAC THEN REFL_TAC) 182in 183 CONV_TAC (K unbeta_goal) THEN MAP_EVERY ABB' (safe_inst_sort tminst) 184end gl; 185 186fun UNABBREV_TAC s = 187 FIRST_X_ASSUM(SUBST_ALL_TAC o 188 assert(equal s o fst o dest_var o lhs o concl) o 189 DeAbbrev); 190 191val UNABBREV_ALL_TAC = 192 let fun ttac th0 = 193 let val th = DeAbbrev th0 194 in SUBST_ALL_TAC th ORELSE ASSUME_TAC th 195 end 196 in 197 REPEAT (FIRST_X_ASSUM ttac) 198end 199 200fun RM_ABBREV_TAC s = 201 FIRST_X_ASSUM (K ALL_TAC o 202 assert(equal s o fst o dest_var o lhs o concl) o 203 DeAbbrev) 204 205val RM_ALL_ABBREVS_TAC = REPEAT (FIRST_X_ASSUM (K ALL_TAC o DeAbbrev)) 206 207(*---------------------------------------------------------------------------*) 208(* Given an abbreviation context, and a goal with possibly more abbrevs, *) 209(* reabbreviate the goal. *) 210(*---------------------------------------------------------------------------*) 211 212fun CNTXT_REABBREV_TAC abbrevs (gl as (asl,_)) = 213 let val abbrevs' = filter is_abbrev asl 214 val ordered_abbrevs = topsort compare_abbrev (abbrevs@abbrevs') 215 val lrs = map (dest_eq o rand) ordered_abbrevs 216 in UNABBREV_ALL_TAC THEN MAP_EVERY (uncurry ABB) lrs 217 end gl; 218 219(*---------------------------------------------------------------------------*) 220(* Execute a tactic in a goal with no abbreviations, then restore the *) 221(* abbrevs, also taking account of any new abbreviations that came in from *) 222(* the application of the tactic. *) 223(*---------------------------------------------------------------------------*) 224 225fun WITHOUT_ABBREVS tac (gl as (asl,_)) = 226 let val abbrevs = filter is_abbrev asl 227 in UNABBREV_ALL_TAC THEN tac THEN CNTXT_REABBREV_TAC abbrevs 228 end gl; 229 230(*---------------------------------------------------------------------------*) 231(* REABBREV_TAC ought to be called after BasicProvers.LET_ELIM_TAC, which *) 232(* introduces an abbrev, but doesn't propagate the abbrev. to the other *) 233(* assumptions. This has been done in basicProof/BasicProvers. *) 234(*---------------------------------------------------------------------------*) 235 236val REABBREV_TAC = WITHOUT_ABBREVS ALL_TAC; 237 238(*---------------------------------------------------------------------------*) 239(* ABBRS_THEN: expand specified abbreviations before applying a tactic. *) 240(* Typically, the abbreviations are designated in the thm list of a *) 241(* simplification tactic thusly: *) 242(* *) 243(* ASM_SIMP_TAC ss [ ..., Abbr`m`, ... ] *) 244(* *) 245(* which says to find and expand the abbreviation *) 246(* *) 247(* Abbrev (m = tm) *) 248(* *) 249(* in the assumptions of the goal before proceeding with simplification. *) 250(*---------------------------------------------------------------------------*) 251 252fun ABBRS_THEN thl_tac thl = 253 let val (abbrs, rest) = List.partition is_abbr thl 254 in 255 MAP_EVERY (UNABBREV_TAC o dest_abbr) abbrs THEN thl_tac rest 256 end 257 258val MK_ABBREVS_OLDSTYLE = 259 RULE_ASSUM_TAC (fn th => (th |> DeAbbrev |> SYM) handle HOL_ERR _ => th) 260 261 262 263(*---------------------------------------------------------------------------*) 264(* Support for user-defined labels. *) 265(*---------------------------------------------------------------------------*) 266 267val DEST_LABEL_CONV = REWR_CONV label_def 268 269val DEST_LABELS_CONV = PURE_REWRITE_CONV [label_def] 270 271val DEST_LABEL = CONV_RULE DEST_LABEL_CONV 272val DEST_LABELS = CONV_RULE DEST_LABELS_CONV 273 274val DEST_LABELS_TAC = CONV_TAC DEST_LABELS_CONV THEN RULE_ASSUM_TAC DEST_LABELS 275 276fun lb s = mk_var(s, label_ty); 277fun LB s = REFL (lb s) 278 279fun MK_LABEL(s, th) = EQ_MP (SYM (SPECL [lb s, concl th] label_def)) th 280 281fun ASSUME_NAMED_TAC s bth : tactic = ASSUME_TAC (MK_LABEL(s, bth)) 282 283(*---------------------------------------------------------------------------*) 284(* Given an LB encoded label reference, finds a corresponding term in the *) 285(* assumption list. *) 286(*---------------------------------------------------------------------------*) 287 288fun find_labelled_assumption labelth asl = let 289 val labname = dest_label_ref labelth 290 fun matching_asm t = 291 (#1 (dest_label t) = labname) handle HOL_ERR _ => false 292in 293 case List.find matching_asm asl of 294 SOME t => DEST_LABEL (ASSUME t) 295 | NONE => raise ERR "find_labelled_assumption" 296 ("No assumption with label \""^labname^"\"") 297end; 298 299fun LABEL_ASSUM s ttac (asl, w) = 300 ttac (find_labelled_assumption (LB s) asl) (asl, w) 301 302(*---------------------------------------------------------------------------*) 303(* LABEL_X_ASSUM is almost identical to LABEL_ASSUM. But it is not applied *) 304(* to the goal, but to a goal with the labelled assumption removed. *) 305(*---------------------------------------------------------------------------*) 306 307fun name_assoc s [] = NONE 308 | name_assoc s (tm::rst) = 309 case total dest_label tm 310 of NONE => name_assoc s rst 311 | SOME (n,tm') => if s=n then SOME(tm,(n,tm')) 312 else name_assoc s rst; 313 314fun LABEL_X_ASSUM s ttac : tactic = 315 fn (asl,w) => 316 case name_assoc s asl 317 of NONE => raise ERR "LABEL_X_ASSUM" 318 ("Can't find term named by "^Lib.quote s^" in assumptions") 319 | SOME(named_tm,_) 320 => ttac (DEST_LABEL(ASSUME named_tm)) 321 (op_set_diff aconv asl [named_tm],w); 322 323(*---------------------------------------------------------------------------*) 324(* Given a list of theorems thl and a list of assumptions asl, return a list *) 325(* consisting of (a) the elements of thl that are not just tags signifying *) 326(* which elements of asl to assume; (b) the non-labelled elements of asl *) 327(* (just ASSUME'd); (c) the elements of asl having labels obtained by *) 328(* looking at the dummy theorems in thl of the form |- label = label. This *) 329(* means that some labelled elements of asl might be excluded. *) 330(*---------------------------------------------------------------------------*) 331 332fun LLABEL_RESOLVE thl asl = let 333 val (labelled_asms, other_asms) = List.partition is_label asl 334 val (labelrefs, realths) = List.partition is_label_ref thl 335 val wanted_lab_assums = 336 map (fn lb => find_labelled_assumption lb labelled_asms) labelrefs 337in 338 map ASSUME other_asms @ wanted_lab_assums @ realths 339end 340 341fun LABEL_RESOLVE th (asl, w) = hd (LLABEL_RESOLVE [th] asl) 342 343end 344