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