15481
|
1 |
(* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- *)
|
|
2 |
(* Title: libs/term_lib.ML
|
|
3 |
Author: Lucas Dixon, University of Edinburgh
|
|
4 |
lucasd@dai.ed.ac.uk
|
|
5 |
Created: 17 Aug 2002
|
|
6 |
*)
|
|
7 |
(* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- *)
|
|
8 |
(* DESCRIPTION:
|
|
9 |
|
|
10 |
Additional code to work with terms.
|
|
11 |
|
|
12 |
*)
|
|
13 |
(* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- *)
|
|
14 |
signature TERM_LIB =
|
|
15 |
sig
|
|
16 |
val fo_term_height : Term.term -> int
|
|
17 |
val ho_term_height : Term.term -> int
|
|
18 |
|
|
19 |
val current_sign : unit -> Sign.sg
|
|
20 |
|
|
21 |
structure fvartabS : TABLE
|
|
22 |
|
|
23 |
(* Matching/unification with exceptions handled *)
|
|
24 |
val clean_match : Type.tsig -> Term.term * Term.term
|
|
25 |
-> ((Term.indexname * Term.typ) list
|
|
26 |
* (Term.indexname * Term.term) list) Library.option
|
|
27 |
val clean_unify : Sign.sg -> int -> Term.term * Term.term
|
|
28 |
-> ((Term.indexname * Term.typ) list
|
|
29 |
* (Term.indexname * Term.term) list) Seq.seq
|
|
30 |
|
|
31 |
(* managing variables in terms, can doing conversions *)
|
|
32 |
val bounds_to_frees : Term.term -> Term.term
|
|
33 |
val bounds_to_frees_with_vars :
|
|
34 |
(string * Term.typ) list -> Term.term -> Term.term
|
|
35 |
|
|
36 |
val change_bounds_to_frees : Term.term -> Term.term
|
|
37 |
val change_frees_to_vars : Term.term -> Term.term
|
|
38 |
val change_vars_to_frees : Term.term -> Term.term
|
|
39 |
val loose_bnds_to_frees :
|
|
40 |
(string * Term.typ) list -> Term.term -> Term.term
|
|
41 |
|
|
42 |
(* make all variables named uniquely *)
|
|
43 |
val unique_namify : Term.term -> Term.term
|
|
44 |
|
|
45 |
(* breasking up a term and putting it into a normal form
|
|
46 |
independent of internal term context *)
|
|
47 |
val cleaned_term_conc : Term.term -> Term.term
|
|
48 |
val cleaned_term_parts : Term.term -> Term.term list * Term.term
|
|
49 |
val cterm_of_term : Term.term -> Thm.cterm
|
|
50 |
|
|
51 |
(* terms of theorems and subgoals *)
|
|
52 |
val term_of_thm : Thm.thm -> Term.term
|
|
53 |
val get_prems_of_sg_term : Term.term -> Term.term list
|
|
54 |
val triv_thm_from_string : string -> Thm.thm
|
|
55 |
(* val make_term_into_simp_thm :
|
|
56 |
(string * Term.typ) list -> Sign.sg -> Term.term -> Thm.thm
|
|
57 |
val thms_of_prems_in_goal : int -> Thm.thm -> Thm.thm list
|
|
58 |
*)
|
|
59 |
|
|
60 |
|
|
61 |
(* some common term manipulations *)
|
|
62 |
val try_dest_Goal : Term.term -> Term.term
|
|
63 |
val try_dest_Trueprop : Term.term -> Term.term
|
|
64 |
|
|
65 |
val bot_left_leaf_of : Term.term -> Term.term
|
|
66 |
|
|
67 |
(* term containing another term - an embedding check *)
|
|
68 |
val term_contains : Term.term -> Term.term -> bool
|
|
69 |
|
|
70 |
(* name-convertable checking - like ae-convertable, but allows for
|
|
71 |
var's and free's to be mixed - and doesn't used buggy code. :-) *)
|
|
72 |
val get_name_eq_member : Term.term -> Term.term list -> Term.term option
|
|
73 |
val name_eq_member : Term.term -> Term.term list -> bool
|
|
74 |
val term_name_eq :
|
|
75 |
Term.term ->
|
|
76 |
Term.term ->
|
|
77 |
(Term.term * Term.term) list ->
|
|
78 |
(Term.term * Term.term) list Library.option
|
|
79 |
|
|
80 |
(* is the typ a function or is it atomic *)
|
|
81 |
val is_fun_typ : Term.typ -> bool
|
|
82 |
val is_atomic_typ : Term.typ -> bool
|
|
83 |
|
|
84 |
(* variable analysis *)
|
|
85 |
val is_some_kind_of_var : Term.term -> bool
|
|
86 |
val same_var_check :
|
|
87 |
''a -> ''b -> (''a * ''b) list -> (''a * ''b) list Library.option
|
|
88 |
val has_new_vars : Term.term * Term.term -> bool
|
|
89 |
val has_new_typ_vars : Term.term * Term.term -> bool
|
|
90 |
(* checks to see if the lhs -> rhs is a invalid rewrite rule *)
|
|
91 |
val is_not_valid_rwrule : Type.tsig -> (Term.term * Term.term) -> bool
|
|
92 |
|
|
93 |
(* get the frees in a term that are of atomic type, ie non-functions *)
|
|
94 |
val atomic_frees_of_term : Term.term -> (string * Term.typ) list
|
|
95 |
|
|
96 |
(* Isar term skolemisationm and unsolemisation *)
|
|
97 |
(* I think this is written also in IsarRTechn and also in somewhere else *)
|
|
98 |
(* val skolemise_term : (string,Term.typ) list -> Term.term -> Term.term
|
|
99 |
val unskolemise_term : (string,Term.typ) list -> Term.term -> Term.term *)
|
|
100 |
val unskolemise_all_term :
|
|
101 |
Term.term ->
|
|
102 |
(((string * Term.typ) * string) list * Term.term)
|
|
103 |
|
|
104 |
(* given a string describing term then a string for its type, returns
|
|
105 |
read term *)
|
|
106 |
val readwty : string -> string -> Term.term
|
|
107 |
|
|
108 |
(* pretty stuff *)
|
|
109 |
val pp_term : Term.term -> unit
|
|
110 |
val pretty_print_sort : string list -> string
|
|
111 |
val pretty_print_term : Term.term -> string
|
|
112 |
val pretty_print_type : Term.typ -> string
|
|
113 |
val pretty_print_typelist :
|
|
114 |
Term.typ list -> (Term.typ -> string) -> string
|
|
115 |
|
|
116 |
val string_of_term : Term.term -> string
|
|
117 |
|
|
118 |
(* these are perhaps redundent, check the standard basis
|
|
119 |
lib for generic versions for any datatype? *)
|
|
120 |
val writesort : string list -> unit
|
|
121 |
val writeterm : Term.term -> unit
|
|
122 |
val writetype : Term.typ -> unit
|
|
123 |
end
|
|
124 |
|
|
125 |
|
|
126 |
structure TermLib : TERM_LIB =
|
|
127 |
struct
|
|
128 |
|
|
129 |
(* Two kinds of depth measure for HOAS terms, a first order (flat) and a
|
|
130 |
higher order one.
|
|
131 |
Note: not stable of eta-contraction: embedding eta-expands term,
|
|
132 |
thus we assume eta-expanded *)
|
|
133 |
fun fo_term_height (a $ b) =
|
|
134 |
IsaPLib.max (1 + fo_term_height b, (fo_term_height a))
|
|
135 |
| fo_term_height (Abs(_,_,t)) = fo_term_height t
|
|
136 |
| fo_term_height _ = 0;
|
|
137 |
|
|
138 |
fun ho_term_height (a $ b) =
|
|
139 |
1 + (IsaPLib.max (ho_term_height b, ho_term_height a))
|
|
140 |
| ho_term_height (Abs(_,_,t)) = ho_term_height t
|
|
141 |
| ho_term_height _ = 0;
|
|
142 |
|
|
143 |
(* Higher order matching with exception handled *)
|
|
144 |
(* returns optional instantiation *)
|
|
145 |
fun clean_match tsig (a as (pat, t)) =
|
|
146 |
Some (Pattern.match tsig a) handle Pattern.MATCH => None;
|
|
147 |
(* Higher order unification with exception handled, return the instantiations *)
|
|
148 |
(* given Signature, max var index, pat, tgt *)
|
|
149 |
(* returns Seq of instantiations *)
|
|
150 |
fun clean_unify sgn ix (a as (pat, tgt)) =
|
|
151 |
let
|
|
152 |
(* type info will be re-derived, maybe this can be cached
|
|
153 |
for efficiency? *)
|
|
154 |
val pat_ty = Term.type_of pat;
|
|
155 |
val tgt_ty = Term.type_of tgt;
|
|
156 |
(* is it OK to ignore the type instantiation info?
|
|
157 |
or should I be using it? *)
|
|
158 |
val typs_unify =
|
|
159 |
(Some (Type.unify (Sign.tsig_of sgn) (Term.Vartab.empty, ix)
|
|
160 |
(pat_ty, tgt_ty)))
|
|
161 |
handle Type.TUNIFY => None;
|
|
162 |
in
|
|
163 |
case typs_unify of
|
|
164 |
Some (typinsttab, ix2) =>
|
|
165 |
let
|
|
166 |
(* is it right to throw away teh flexes?
|
|
167 |
or should I be using them somehow? *)
|
|
168 |
fun mk_insts (env,flexflexes) =
|
|
169 |
(Vartab.dest (Envir.type_env env), Envir.alist_of env);
|
|
170 |
val initenv = Envir.Envir {asol = Vartab.empty,
|
|
171 |
iTs = typinsttab, maxidx = ix2};
|
|
172 |
val useq = (Unify.unifiers (sgn,initenv,[a]))
|
|
173 |
handle Library.LIST _ => Seq.empty
|
|
174 |
| Term.TERM _ => Seq.empty;
|
|
175 |
fun clean_unify' useq () =
|
|
176 |
(case (Seq.pull useq) of
|
|
177 |
None => None
|
|
178 |
| Some (h,t) => Some (mk_insts h, Seq.make (clean_unify' t)))
|
|
179 |
handle Library.LIST _ => None
|
|
180 |
| Term.TERM _ => None;
|
|
181 |
in
|
|
182 |
(Seq.make (clean_unify' useq))
|
|
183 |
end
|
|
184 |
| None => Seq.empty
|
|
185 |
end;
|
|
186 |
|
|
187 |
fun asm_mk t = (assume (cterm_of (Theory.sign_of (the_context())) t));
|
|
188 |
fun asm_read s =
|
|
189 |
(Thm.assume (read_cterm (Theory.sign_of (Context.the_context())) (s,propT)));
|
|
190 |
|
|
191 |
|
|
192 |
(* more pretty printing code for Isabelle terms etc *)
|
|
193 |
|
|
194 |
|
|
195 |
(* pretty_print_typelist l f = print a typelist.
|
|
196 |
l = list of types to print : typ list
|
|
197 |
f = function used to print a single type : typ -> string
|
|
198 |
*)
|
|
199 |
fun pretty_print_typelist [] f = ""
|
|
200 |
| pretty_print_typelist [(h: typ)] (f : typ -> string) = (f h)
|
|
201 |
| pretty_print_typelist ((h: typ) :: t) (f : typ -> string) =
|
|
202 |
(f h) ^ ", " ^ (pretty_print_typelist t f);
|
|
203 |
|
|
204 |
|
|
205 |
|
|
206 |
(* pretty_print_sort s = print a sort
|
|
207 |
s = sort to print : string list
|
|
208 |
*)
|
|
209 |
fun pretty_print_sort [] = ""
|
|
210 |
| pretty_print_sort ([h]) = "\"" ^ h ^ "\""
|
|
211 |
| pretty_print_sort (h :: t) = "\"" ^ h ^ "\"," ^ (pretty_print_sort t);
|
|
212 |
|
|
213 |
|
|
214 |
(* pretty_print_type t = print a type
|
|
215 |
t = type to print : type
|
|
216 |
*)
|
|
217 |
fun pretty_print_type (Type (n, l)) =
|
|
218 |
"Type(\"" ^ n ^ "\", [" ^ (pretty_print_typelist l pretty_print_type) ^ "])"
|
|
219 |
| pretty_print_type (TFree (n, s)) =
|
|
220 |
"TFree(\"" ^ n ^ "\", [" ^ (pretty_print_sort s) ^ "])"
|
|
221 |
| pretty_print_type (TVar ((n, i), s)) =
|
|
222 |
"TVar( (\"" ^ n ^ "\", " ^ (string_of_int i) ^ "), [" ^ (pretty_print_sort s) ^ "])";
|
|
223 |
|
|
224 |
|
|
225 |
(* pretty_print_term t = print a term prints types and sorts too.
|
|
226 |
t = term to print : term
|
|
227 |
*)
|
|
228 |
fun pretty_print_term (Const (s, t)) =
|
|
229 |
"Const(\"" ^ s ^ "\", " ^ (pretty_print_type t) ^ ")"
|
|
230 |
| pretty_print_term (Free (s, t)) =
|
|
231 |
"Free(\"" ^ s ^ "\", " ^ (pretty_print_type t) ^ ")"
|
|
232 |
| pretty_print_term (Var ((n, i), t)) =
|
|
233 |
"Var( (\"" ^ n ^ "\"," ^ (string_of_int i) ^ "), " ^ (pretty_print_type t) ^ ")"
|
|
234 |
| pretty_print_term (Bound i) =
|
|
235 |
"Bound(" ^ (string_of_int i) ^ ")"
|
|
236 |
| pretty_print_term (Abs (s, t, r)) =
|
|
237 |
"Abs(\"" ^ s ^ "\"," ^ (pretty_print_type t) ^ ", \n " ^ (pretty_print_term r) ^ ")"
|
|
238 |
| pretty_print_term (op $ (t1, t2)) =
|
|
239 |
"(" ^ (pretty_print_term t1) ^ ") $\n (" ^ (pretty_print_term t2) ^ ")";
|
|
240 |
|
|
241 |
(* Write the term out nicly instead of just creating a string for it *)
|
|
242 |
fun writeterm t = writeln (pretty_print_term t);
|
|
243 |
fun writetype t = writeln (pretty_print_type t);
|
|
244 |
fun writesort s = writeln (pretty_print_sort s);
|
|
245 |
|
|
246 |
|
|
247 |
(* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- *)
|
|
248 |
(* Turn on show types *)
|
|
249 |
(* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- *)
|
|
250 |
|
|
251 |
(* if (!show_types) then true else set show_types; *)
|
|
252 |
|
|
253 |
(* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- *)
|
|
254 |
(* functions *)
|
|
255 |
(* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- *)
|
|
256 |
|
|
257 |
fun current_sign () = sign_of (the_context());
|
|
258 |
fun cterm_of_term (t : term) = cterm_of (current_sign()) t;
|
|
259 |
fun term_of_thm t = (Thm.prop_of t);
|
|
260 |
|
|
261 |
(* little function to make a trueprop of anything by putting a P
|
|
262 |
function in front of it...
|
|
263 |
fun HOL_mk_term_prop t =
|
|
264 |
((Const("Trueprop", Type("fun",
|
|
265 |
[Type("bool", []), Type("prop", [])]))) $
|
|
266 |
((Free("P", Type("fun", [type_of t,
|
|
267 |
Type("bool", [])]))) $ t));
|
|
268 |
|
|
269 |
*)
|
|
270 |
|
|
271 |
fun string_of_term t =
|
|
272 |
(Sign.string_of_term (current_sign()) t);
|
|
273 |
|
|
274 |
(*
|
|
275 |
(allt as (Const("Trueprop", ty) $ m)) =
|
|
276 |
(string_of_cterm (cterm_of_term allt))
|
|
277 |
| string_of_term (t : term) =
|
|
278 |
string_of_cterm (cterm_of_term (HOL_mk_term_prop t));
|
|
279 |
*)
|
|
280 |
|
|
281 |
(* creates a simple cterm of the term if it's not already a prop by
|
|
282 |
prefixing it with a polymorphic function P, then create the cterm
|
|
283 |
and print that. Handy tool for printing terms that are not
|
|
284 |
already propositions, or not cterms.
|
|
285 |
*)
|
|
286 |
fun pp_term t = writeln (string_of_term t);
|
|
287 |
|
|
288 |
(* create a trivial HOL thm from anything... *)
|
|
289 |
fun triv_thm_from_string s =
|
|
290 |
Thm.trivial (cterm_of (current_sign()) (read s));
|
|
291 |
|
|
292 |
(* Checks if vars could be the same - alpha convertable
|
|
293 |
w.r.t. previous vars, a and b are assumed to be vars,
|
|
294 |
free vars, but not bound vars,
|
|
295 |
Note frees and vars must all have unique names. *)
|
|
296 |
fun same_var_check a b L =
|
|
297 |
let
|
|
298 |
fun bterm_from t [] = None
|
|
299 |
| bterm_from t ((a,b)::m) =
|
|
300 |
if t = a then Some b else bterm_from t m
|
|
301 |
|
|
302 |
val bl_opt = bterm_from a L
|
|
303 |
in
|
|
304 |
case bterm_from a L of
|
|
305 |
None => Some ((a,b)::L)
|
|
306 |
| Some b2 => if b2 = b then Some L else None
|
|
307 |
end;
|
|
308 |
|
|
309 |
(* FIXME: make more efficient, only require a single new var! *)
|
|
310 |
(* check if the new term has any meta variables not in the old term *)
|
|
311 |
fun has_new_vars (old, new) =
|
|
312 |
(case IsaPLib.lrem (op =) (Term.term_vars old) (Term.term_vars new) of
|
|
313 |
[] => false
|
|
314 |
| (_::_) => true);
|
|
315 |
(* check if the new term has any meta variables not in the old term *)
|
|
316 |
fun has_new_typ_vars (old, new) =
|
|
317 |
(case IsaPLib.lrem (op =) (Term.term_tvars old) (Term.term_tvars new) of
|
|
318 |
[] => false
|
|
319 |
| (_::_) => true);
|
|
320 |
|
|
321 |
(* working with Isar terms and their skolemisation(s) *)
|
|
322 |
(* val skolemise_term : (string,Term.typ) list -> Term.term -> Term.term
|
|
323 |
val unskolemise_term : (string,Term.typ) list -> Term.term -> Term.term
|
|
324 |
*)
|
|
325 |
|
|
326 |
(* cunning version *)
|
|
327 |
|
|
328 |
(* This version avoids name conflicts that might be intorduced by
|
|
329 |
unskolemisation, and returns a list of (string * Term.typ) * string,
|
|
330 |
where the outer string is the original name, and the inner string is
|
|
331 |
the new name, and the type is the type of the free variable that was
|
|
332 |
renamed. *)
|
|
333 |
local
|
|
334 |
fun myadd (n,ty) (L as (renames, names)) =
|
|
335 |
let val n' = Syntax.dest_skolem n in
|
|
336 |
case (Library.find_first (fn (_,n2) => (n2 = n)) renames) of
|
|
337 |
None =>
|
|
338 |
let val renamedn = Term.variant names n' in
|
|
339 |
(renamedn, (((renamedn, ty), n) :: renames,
|
|
340 |
renamedn :: names)) end
|
|
341 |
| (Some ((renamedn, _), _)) => (renamedn, L)
|
|
342 |
end
|
|
343 |
handle LIST _ => (n, L);
|
|
344 |
|
|
345 |
fun unsk (L,f) (t1 $ t2) =
|
|
346 |
let val (L', t1') = unsk (L, I) t1
|
|
347 |
in unsk (L', (fn x => f (t1' $ x))) t2 end
|
|
348 |
| unsk (L,f) (Abs(n,ty,t)) =
|
|
349 |
unsk (L, (fn x => Abs(n,ty,x))) t
|
|
350 |
| unsk (L, f) (Free (n,ty)) =
|
|
351 |
let val (renamed_n, L') = myadd (n ,ty) L
|
|
352 |
in (L', f (Free (renamed_n, ty))) end
|
|
353 |
| unsk (L, f) l = (L, f l);
|
|
354 |
in
|
|
355 |
fun unskolemise_all_term t =
|
|
356 |
let
|
|
357 |
val names = Term.add_term_names (t,[])
|
|
358 |
val ((renames,names'),t') = unsk (([], names),I) t
|
|
359 |
in (renames,t') end;
|
|
360 |
end
|
|
361 |
|
|
362 |
(* fun unskolemise_all_term t =
|
|
363 |
let
|
|
364 |
fun fmap fv =
|
|
365 |
let (n,ty) = (Term.dest_Free fv) in
|
|
366 |
Some (fv, Free (Syntax.dest_skolem n, ty)) handle LIST _ => None
|
|
367 |
end
|
|
368 |
val substfrees = mapfilter fmap (Term.term_frees t)
|
|
369 |
in
|
|
370 |
Term.subst_free substfrees t
|
|
371 |
end; *)
|
|
372 |
|
|
373 |
(* true if the type t is a function *)
|
|
374 |
fun is_fun_typ (Type(s, l)) =
|
|
375 |
if s = "fun" then true else false
|
|
376 |
| is_fun_typ _ = false;
|
|
377 |
|
|
378 |
val is_atomic_typ = not o is_fun_typ;
|
|
379 |
|
|
380 |
(* get the frees in a term that are of atomic type, ie non-functions *)
|
|
381 |
val atomic_frees_of_term =
|
|
382 |
filter (is_atomic_typ o snd)
|
|
383 |
o map Term.dest_Free
|
|
384 |
o Term.term_frees;
|
|
385 |
|
|
386 |
|
|
387 |
(* read in a string and a top-level type and this will give back a term *)
|
|
388 |
fun readwty tstr tystr =
|
|
389 |
let
|
|
390 |
val sgn = Theory.sign_of (the_context())
|
|
391 |
in
|
|
392 |
Sign.simple_read_term sgn (Sign.read_typ (sgn, K None) tystr) tstr
|
|
393 |
end;
|
|
394 |
|
|
395 |
|
|
396 |
(* first term is equal to the second in some name convertable
|
|
397 |
way... Note: This differs from the aeconv in the Term.ML file of
|
|
398 |
Isabelle in that it allows a var to be alpha-equiv to a free var.
|
|
399 |
|
|
400 |
Also, the isabelle term.ML version of aeconv uses a
|
|
401 |
function that it claims doesn't work! *)
|
|
402 |
|
|
403 |
fun term_name_eq (Abs(_,ty1,t1)) (Abs(_,ty2,t2)) l =
|
|
404 |
if ty1 = ty2 then term_name_eq t1 t2 l
|
|
405 |
else None
|
|
406 |
|
|
407 |
| term_name_eq (ah $ at) (bh $ bt) l =
|
|
408 |
let
|
|
409 |
val lopt = (term_name_eq ah bh l)
|
|
410 |
in
|
|
411 |
if is_some lopt then
|
|
412 |
term_name_eq at bt (the lopt)
|
|
413 |
else
|
|
414 |
None
|
|
415 |
end
|
|
416 |
|
|
417 |
| term_name_eq (Const(a,T)) (Const(b,U)) l =
|
|
418 |
if a=b andalso T=U then Some l
|
|
419 |
else None
|
|
420 |
|
|
421 |
| term_name_eq (a as Free(s1,ty1)) (b as Free(s2,ty2)) l =
|
|
422 |
same_var_check a b l
|
|
423 |
|
|
424 |
| term_name_eq (a as Free(s1,ty1)) (b as Var(n2,ty2)) l =
|
|
425 |
same_var_check a b l
|
|
426 |
|
|
427 |
| term_name_eq (a as Var(n1,ty1)) (b as Free(s2,ty2)) l =
|
|
428 |
same_var_check a b l
|
|
429 |
|
|
430 |
| term_name_eq (a as Var(n1,ty1)) (b as Var(n2,ty2)) l =
|
|
431 |
same_var_check a b l
|
|
432 |
|
|
433 |
| term_name_eq (Bound i) (Bound j) l =
|
|
434 |
if i = j then Some l else None
|
|
435 |
|
|
436 |
| term_name_eq a b l = ((*writeln ("unchecked case:\n" ^ "a:\n" ^ (pretty_print_term a) ^ "\nb:\n" ^ (pretty_print_term b));*) None);
|
|
437 |
|
|
438 |
(* checks to see if the term in a name-equivalent member of the list of terms. *)
|
|
439 |
fun get_name_eq_member a [] = None
|
|
440 |
| get_name_eq_member a (h :: t) =
|
|
441 |
if is_some (term_name_eq a h []) then Some h
|
|
442 |
else get_name_eq_member a t;
|
|
443 |
|
|
444 |
fun name_eq_member a [] = false
|
|
445 |
| name_eq_member a (h :: t) =
|
|
446 |
if is_some (term_name_eq a h []) then true
|
|
447 |
else name_eq_member a t;
|
|
448 |
|
|
449 |
(* true if term is a variable *)
|
|
450 |
fun is_some_kind_of_var (Free(s, ty)) = true
|
|
451 |
| is_some_kind_of_var (Var(i, ty)) = true
|
|
452 |
| is_some_kind_of_var (Bound(i)) = true
|
|
453 |
| is_some_kind_of_var _ = false;
|
|
454 |
|
|
455 |
(* checks to see if the lhs -> rhs is a invalid rewrite rule *)
|
|
456 |
(* FIXME: we should really check that there is a subterm on the lhs
|
|
457 |
which embeds into the rhs, this would be much closer to the normal
|
|
458 |
notion of valid wave rule - ie there exists at least one case where it
|
|
459 |
is a valid wave rule... *)
|
|
460 |
fun is_not_valid_rwrule tysig (lhs, rhs) =
|
|
461 |
(Pattern.matches_subterm tysig (lhs, rhs)) orelse
|
|
462 |
has_new_vars (lhs,rhs) orelse
|
|
463 |
has_new_typ_vars (lhs,rhs);
|
|
464 |
|
|
465 |
|
|
466 |
(* first term contains the second in some name convertable way... *)
|
|
467 |
(* note: this is equivalent to an alpha-convertable emedding *)
|
|
468 |
(* takes as args: term containing a, term contained b,
|
|
469 |
(bound vars of a, bound vars of b),
|
|
470 |
current alpha-conversion-pairs,
|
|
471 |
returns: bool:can convert, new alpha-conversion table *)
|
|
472 |
(* in bellow: we *don't* use: a loose notion that only requires
|
|
473 |
variables to match variables, and doesn't worry about the actual
|
|
474 |
pattern in the variables. *)
|
|
475 |
fun term_contains1 (Bs, FVs) (Abs(s,ty,t)) (Abs(s2,ty2,t2)) =
|
|
476 |
if ty = ty2 then
|
|
477 |
term_contains1 ((Some(s,s2,ty)::Bs), FVs) t t2
|
|
478 |
else []
|
|
479 |
|
|
480 |
| term_contains1 T t1 (Abs(s2,ty2,t2)) = []
|
|
481 |
|
|
482 |
| term_contains1 (Bs, FVs) (Abs(s,ty,t)) t2 =
|
|
483 |
term_contains1 (None::Bs, FVs) t t2
|
|
484 |
|
|
485 |
| term_contains1 T (ah $ at) (bh $ bt) =
|
|
486 |
(term_contains1 T ah (bh $ bt)) @
|
|
487 |
(term_contains1 T at (bh $ bt)) @
|
|
488 |
(flat (map (fn inT => (term_contains1 inT at bt))
|
|
489 |
(term_contains1 T ah bh)))
|
|
490 |
|
|
491 |
| term_contains1 T a (bh $ bt) = []
|
|
492 |
|
|
493 |
| term_contains1 T (ah $ at) b =
|
|
494 |
(term_contains1 T ah b) @ (term_contains1 T at b)
|
|
495 |
|
|
496 |
| term_contains1 T a b =
|
|
497 |
(* simple list table lookup to check if a named variable has been
|
|
498 |
mapped to a variable, if not adds the mapping and return some new
|
|
499 |
list mapping, if it is then it checks that the pair are mapped to
|
|
500 |
each other, if so returns the current mapping list, else none. *)
|
|
501 |
let
|
|
502 |
fun bterm_from t [] = None
|
|
503 |
| bterm_from t ((a,b)::m) =
|
|
504 |
if t = a then Some b else bterm_from t m
|
|
505 |
|
|
506 |
(* check to see if, w.r.t. the variable mapping, two terms are leaf
|
|
507 |
terms and are mapped to each other. Note constants are only mapped
|
|
508 |
to the same constant. *)
|
|
509 |
fun same_leaf_check (T as (Bs,FVs)) (Bound i) (Bound j) =
|
|
510 |
let
|
|
511 |
fun aux_chk (i1,i2) [] = false
|
|
512 |
| aux_chk (0,0) ((Some _) :: bnds) = true
|
|
513 |
| aux_chk (i1,0) (None :: bnds) = false
|
|
514 |
| aux_chk (i1,i2) ((Some _) :: bnds) =
|
|
515 |
aux_chk (i1 - 1,i2 - 1) bnds
|
|
516 |
| aux_chk (i1,i2) (None :: bnds) =
|
|
517 |
aux_chk (i1,i2 - 1) bnds
|
|
518 |
in
|
|
519 |
if (aux_chk (i,j) Bs) then [T]
|
|
520 |
else []
|
|
521 |
end
|
|
522 |
| same_leaf_check (T as (Bs,(Fs,Vs)))
|
|
523 |
(a as (Free (an,aty)))
|
|
524 |
(b as (Free (bn,bty))) =
|
|
525 |
(case bterm_from an Fs of
|
|
526 |
Some b2n => if bn = b2n then [T]
|
|
527 |
else [] (* conflict of var name *)
|
|
528 |
| None => [(Bs,((an,bn)::Fs,Vs))])
|
|
529 |
| same_leaf_check (T as (Bs,(Fs,Vs)))
|
|
530 |
(a as (Var (an,aty)))
|
|
531 |
(b as (Var (bn,bty))) =
|
|
532 |
(case bterm_from an Vs of
|
|
533 |
Some b2n => if bn = b2n then [T]
|
|
534 |
else [] (* conflict of var name *)
|
|
535 |
| None => [(Bs,(Fs,(an,bn)::Vs))])
|
|
536 |
| same_leaf_check T (a as (Const _)) (b as (Const _)) =
|
|
537 |
if a = b then [T] else []
|
|
538 |
| same_leaf_check T _ _ = []
|
|
539 |
|
|
540 |
in
|
|
541 |
same_leaf_check T a b
|
|
542 |
end;
|
|
543 |
|
|
544 |
(* wrapper for term_contains1: checks if the term "a" contains in
|
|
545 |
some embedded way, (w.r.t. name -convertable) the term "b" *)
|
|
546 |
fun term_contains a b =
|
|
547 |
case term_contains1 ([],([],[])) a b of
|
|
548 |
(_ :: _) => true
|
|
549 |
| [] => false;
|
|
550 |
|
|
551 |
|
|
552 |
(* pp_term a; pp_term b; writeln "EQTerm matches are: "; map (fn (a,b) => writeln ("(" ^ (string_of_term a) ^ ", " ^ (string_of_term b) ^ ")")) L;*)
|
|
553 |
|
|
554 |
|
|
555 |
(* change all bound variables to see ones with appropriate name and
|
|
556 |
type *)
|
|
557 |
|
|
558 |
(* naming convention is OK as we use 'variant' from term.ML *)
|
|
559 |
|
|
560 |
(* Note "bounds_to_frees" defined below, its better and quicker, but
|
|
561 |
keeps the quantifiers handing about, and changes all bounds, not
|
|
562 |
just universally quantified ones. *)
|
|
563 |
fun change_bounds_to_frees t =
|
|
564 |
let
|
|
565 |
val vars = strip_all_vars t
|
|
566 |
val frees_names = map (fn Free(s,n) => s | _ => "") (term_frees t)
|
|
567 |
val body = strip_all_body t
|
|
568 |
|
|
569 |
fun bnds_to_frees [] _ acc = acc
|
|
570 |
| bnds_to_frees ((name,ty)::more) names acc =
|
|
571 |
let
|
|
572 |
val new_name = variant names name
|
|
573 |
in
|
|
574 |
bnds_to_frees more (new_name::names) (Free(new_name,ty)::acc)
|
|
575 |
end
|
|
576 |
in
|
|
577 |
(subst_bounds ((bnds_to_frees vars frees_names []), body))
|
|
578 |
end;
|
|
579 |
|
|
580 |
|
|
581 |
|
|
582 |
structure fvartabS = TableFun(type key = string val ord = string_ord);
|
|
583 |
|
|
584 |
(* a runtime-quick function which makes sure that every variable has a
|
|
585 |
unique name *)
|
|
586 |
fun unique_namify_aux (ntab,(Abs(s,ty,t))) =
|
|
587 |
(case (fvartabS.lookup (ntab,s)) of
|
|
588 |
None =>
|
|
589 |
let
|
|
590 |
val (ntab2,t2) = unique_namify_aux ((fvartabS.update ((s,s),ntab)), t)
|
|
591 |
in
|
|
592 |
(ntab2,Abs(s,ty,t2))
|
|
593 |
end
|
|
594 |
| Some s2 =>
|
|
595 |
let
|
|
596 |
val s_new = (Term.variant (fvartabS.keys ntab) s)
|
|
597 |
val (ntab2,t2) =
|
|
598 |
unique_namify_aux ((fvartabS.update ((s_new,s_new),ntab)), t)
|
|
599 |
in
|
|
600 |
(ntab2,Abs(s_new,ty,t2))
|
|
601 |
end)
|
|
602 |
| unique_namify_aux (ntab,(a $ b)) =
|
|
603 |
let
|
|
604 |
val (ntab1,t1) = unique_namify_aux (ntab,a)
|
|
605 |
val (ntab2,t2) = unique_namify_aux (ntab1,b)
|
|
606 |
in
|
|
607 |
(ntab2, t1$t2)
|
|
608 |
end
|
|
609 |
| unique_namify_aux (nt as (ntab,Const x)) = nt
|
|
610 |
| unique_namify_aux (nt as (ntab,f as Free (s,ty))) =
|
|
611 |
(case (fvartabS.lookup (ntab,s)) of
|
|
612 |
None => ((fvartabS.update ((s,s),ntab)), f)
|
|
613 |
| Some _ => nt)
|
|
614 |
| unique_namify_aux (nt as (ntab,v as Var ((s,i),ty))) =
|
|
615 |
(case (fvartabS.lookup (ntab,s)) of
|
|
616 |
None => ((fvartabS.update ((s,s),ntab)), v)
|
|
617 |
| Some _ => nt)
|
|
618 |
| unique_namify_aux (nt as (ntab, Bound i)) = nt;
|
|
619 |
|
|
620 |
fun unique_namify t =
|
|
621 |
#2 (unique_namify_aux (fvartabS.empty, t));
|
|
622 |
|
|
623 |
(* a runtime-quick function which makes sure that every variable has a
|
|
624 |
unique name and also changes bound variables to free variables, used
|
|
625 |
for embedding checks, Note that this is a pretty naughty term
|
|
626 |
manipulation, which doesn't have necessary relation to the original
|
|
627 |
sematics of the term. This is really a trick for our embedding code. *)
|
|
628 |
|
|
629 |
fun bounds_to_frees_aux T (ntab,(Abs(s,ty,t))) =
|
|
630 |
(case (fvartabS.lookup (ntab,s)) of
|
|
631 |
None =>
|
|
632 |
let
|
|
633 |
val (ntab2,t2) = bounds_to_frees_aux ((s,ty)::T)
|
|
634 |
((fvartabS.update ((s,s),ntab)), t)
|
|
635 |
in
|
|
636 |
(ntab2,Abs(s,ty,t2))
|
|
637 |
end
|
|
638 |
| Some s2 =>
|
|
639 |
let
|
|
640 |
val s_new = (Term.variant (fvartabS.keys ntab) s)
|
|
641 |
val (ntab2,t2) =
|
|
642 |
bounds_to_frees_aux ((s_new,ty)::T)
|
|
643 |
(fvartabS.update (((s_new,s_new),ntab)), t)
|
|
644 |
in
|
|
645 |
(ntab2,Abs(s_new,ty,t2))
|
|
646 |
end)
|
|
647 |
| bounds_to_frees_aux T (ntab,(a $ b)) =
|
|
648 |
let
|
|
649 |
val (ntab1,t1) = bounds_to_frees_aux T (ntab,a)
|
|
650 |
val (ntab2,t2) = bounds_to_frees_aux T (ntab1,b)
|
|
651 |
in
|
|
652 |
(ntab2, t1$t2)
|
|
653 |
end
|
|
654 |
| bounds_to_frees_aux T (nt as (ntab,Const x)) = nt
|
|
655 |
| bounds_to_frees_aux T (nt as (ntab,f as Free (s,ty))) =
|
|
656 |
(case (fvartabS.lookup (ntab,s)) of
|
|
657 |
None => ((fvartabS.update ((s,s),ntab)), f)
|
|
658 |
| Some _ => nt)
|
|
659 |
| bounds_to_frees_aux T (nt as (ntab,v as Var ((s,i),ty))) =
|
|
660 |
(case (fvartabS.lookup (ntab,s)) of
|
|
661 |
None => ((fvartabS.update ((s,s),ntab)), v)
|
|
662 |
| Some _ => nt)
|
|
663 |
| bounds_to_frees_aux T (nt as (ntab, Bound i)) =
|
|
664 |
let
|
|
665 |
val (s,ty) = Library.nth_elem (i,T)
|
|
666 |
in
|
|
667 |
(ntab, Free (s,ty))
|
|
668 |
end;
|
|
669 |
|
|
670 |
|
|
671 |
fun bounds_to_frees t =
|
|
672 |
#2 (bounds_to_frees_aux [] (fvartabS.empty,t));
|
|
673 |
|
|
674 |
fun bounds_to_frees_with_vars vars t =
|
|
675 |
#2 (bounds_to_frees_aux vars (fvartabS.empty,t));
|
|
676 |
|
|
677 |
|
|
678 |
|
|
679 |
(* loose bounds to frees *)
|
|
680 |
fun loose_bnds_to_frees_aux (bnds,vars) (Abs(s,ty,t)) =
|
|
681 |
Abs(s,ty,loose_bnds_to_frees_aux (bnds + 1,vars) t)
|
|
682 |
| loose_bnds_to_frees_aux (bnds,vars) (a $ b) =
|
|
683 |
(loose_bnds_to_frees_aux (bnds,vars) a)
|
|
684 |
$ (loose_bnds_to_frees_aux (bnds,vars) b)
|
|
685 |
| loose_bnds_to_frees_aux (bnds,vars) (t as (Bound i)) =
|
|
686 |
if (bnds <= i) then Free (Library.nth_elem (i - bnds,vars))
|
|
687 |
else t
|
|
688 |
| loose_bnds_to_frees_aux (bnds,vars) t = t;
|
|
689 |
|
|
690 |
|
|
691 |
fun loose_bnds_to_frees vars t =
|
|
692 |
loose_bnds_to_frees_aux (0,vars) t;
|
|
693 |
|
|
694 |
(* puts prems of a theorem into a useful form, (rulify)
|
|
695 |
Note that any loose bound variables are treated as free vars
|
|
696 |
*)
|
|
697 |
(* fun make_term_into_simp_thm vars sgn t =
|
|
698 |
let
|
|
699 |
val triv =
|
|
700 |
Thm.trivial (Thm.cterm_of
|
|
701 |
sgn (loose_bnds_to_frees vars t))
|
|
702 |
in
|
|
703 |
SplitterData.mk_eq (Drule.standard (ObjectLogic.rulify_no_asm triv))
|
|
704 |
end;
|
|
705 |
|
|
706 |
fun thms_of_prems_in_goal i tm=
|
|
707 |
let
|
|
708 |
val goal = (nth_elem (i-1,Thm.prems_of tm))
|
|
709 |
val vars = rev (strip_all_vars goal)
|
|
710 |
val prems = Logic.strip_assums_hyp (strip_all_body goal)
|
|
711 |
val simp_prem_thms =
|
|
712 |
map (make_term_into_simp_thm vars (Thm.sign_of_thm tm)) prems
|
|
713 |
in
|
|
714 |
simp_prem_thms
|
|
715 |
end;
|
|
716 |
*)
|
|
717 |
|
|
718 |
(* replace all universally quantifief variables (at HOL object level)
|
|
719 |
with free vars
|
|
720 |
fun HOL_Alls_to_frees TL (Const("All", _) $ Abs(v, ty, t)) =
|
|
721 |
HOL_Alls_to_frees ((Free (v, ty)) :: TL) t
|
|
722 |
| HOL_Alls_to_frees TL t =
|
|
723 |
(TL,(subst_bounds (TL, t)));
|
|
724 |
*)
|
|
725 |
|
|
726 |
(* this is just a hack for mixing with interactive mode, and using topthm() *)
|
|
727 |
|
|
728 |
fun try_dest_Goal (Const("Goal", _) $ T) = T
|
|
729 |
| try_dest_Goal T = T;
|
|
730 |
|
|
731 |
fun try_dest_Trueprop (Const("Trueprop", _) $ T) = T
|
|
732 |
| try_dest_Trueprop T = T;
|
|
733 |
|
|
734 |
fun bot_left_leaf_of (l $ r) = bot_left_leaf_of l
|
|
735 |
| bot_left_leaf_of (Abs(s,ty,t)) = bot_left_leaf_of t
|
|
736 |
| bot_left_leaf_of x = x;
|
|
737 |
|
|
738 |
|
|
739 |
(* cleaned up normal form version of the subgoal terms conclusion *)
|
|
740 |
fun cleaned_term_conc t =
|
|
741 |
let
|
|
742 |
val concl = Logic.strip_imp_concl (change_bounds_to_frees t)
|
|
743 |
in
|
|
744 |
(try_dest_Trueprop (try_dest_Goal concl))
|
|
745 |
end;
|
|
746 |
|
|
747 |
(* fun get_prems_of_sg_term t =
|
|
748 |
map opt_dest_Trueprop (Logic.strip_imp_prems t); *)
|
|
749 |
|
|
750 |
fun get_prems_of_sg_term t =
|
|
751 |
map try_dest_Trueprop (Logic.strip_assums_hyp t);
|
|
752 |
|
|
753 |
|
|
754 |
(* drop premices, clean bound var stuff, and make a trueprop... *)
|
|
755 |
fun cleaned_term_parts t =
|
|
756 |
let
|
|
757 |
val t2 = (change_bounds_to_frees t)
|
|
758 |
val concl = Logic.strip_imp_concl t2
|
|
759 |
val prems = map try_dest_Trueprop (Logic.strip_imp_prems t2)
|
|
760 |
in
|
|
761 |
(prems, (try_dest_Trueprop (try_dest_Goal concl)))
|
|
762 |
end;
|
|
763 |
|
|
764 |
(* old version
|
|
765 |
fun cleaned_term t =
|
|
766 |
let
|
|
767 |
val concl = (HOLogic.dest_Trueprop (Logic.strip_imp_concl
|
|
768 |
(change_bounds_to_frees t) ))
|
|
769 |
in
|
|
770 |
concl
|
|
771 |
end;
|
|
772 |
*)
|
|
773 |
|
|
774 |
(* change free variables to vars and visa versa *)
|
|
775 |
(* *** check naming is OK, can we just use the vasr old name? *)
|
|
776 |
(* *** Check: Logic.varify and Logic.unvarify *)
|
|
777 |
fun change_vars_to_frees (a$b) =
|
|
778 |
(change_vars_to_frees a) $ (change_vars_to_frees b)
|
|
779 |
| change_vars_to_frees (Abs(s,ty,t)) =
|
|
780 |
(Abs(s,Type.varifyT ty,change_vars_to_frees t))
|
|
781 |
| change_vars_to_frees (Var((s,i),ty)) = (Free(s,Type.unvarifyT ty))
|
|
782 |
| change_vars_to_frees l = l;
|
|
783 |
|
|
784 |
fun change_frees_to_vars (a$b) =
|
|
785 |
(change_frees_to_vars a) $ (change_frees_to_vars b)
|
|
786 |
| change_frees_to_vars (Abs(s,ty,t)) =
|
|
787 |
(Abs(s,Type.varifyT ty,change_frees_to_vars t))
|
|
788 |
| change_frees_to_vars (Free(s,ty)) = (Var((s,0),Type.varifyT ty))
|
|
789 |
| change_frees_to_vars l = l;
|
|
790 |
|
|
791 |
|
|
792 |
end;
|
|
793 |
|
|
794 |
|
|
795 |
|
|
796 |
(* ignores lambda abstractions, ie (\x y = y)
|
|
797 |
same as embedding check code, ie. (f a b) = can "a" be embedded in "b"
|
|
798 |
*)
|
|
799 |
(* fun term_is_same_or_simpler_than (Abs(s,ty,t)) b =
|
|
800 |
term_is_same_or_simpler_than t b
|
|
801 |
|
|
802 |
| term_is_same_or_simpler_than a (Abs(s,ty,t)) =
|
|
803 |
term_is_same_or_simpler_than a t
|
|
804 |
|
|
805 |
| term_is_same_or_simpler_than (ah $ at) (bh $ bt) =
|
|
806 |
(term_is_same_or_simpler_than (ah $ at) bh) orelse
|
|
807 |
(term_is_same_or_simpler_than (ah $ at) bt) orelse
|
|
808 |
((term_is_same_or_simpler_than ah bh) andalso
|
|
809 |
(term_is_same_or_simpler_than at bt))
|
|
810 |
|
|
811 |
| term_is_same_or_simpler_than (ah $ at) b = false
|
|
812 |
|
|
813 |
| term_is_same_or_simpler_than a (bh $ bt) =
|
|
814 |
(term_is_same_or_simpler_than a bh) orelse
|
|
815 |
(term_is_same_or_simpler_than a bt)
|
|
816 |
|
|
817 |
| term_is_same_or_simpler_than a b =
|
|
818 |
if a = b then true else false;
|
|
819 |
*)
|
|
820 |
|
|
821 |
(* fun term_is_simpler_than t1 t2 =
|
|
822 |
(are_different_terms t1 t2) andalso
|
|
823 |
(term_is_same_or_simpler_than t1 t2);
|
|
824 |
*)
|