author | haftmann |
Mon, 07 Nov 2005 12:06:11 +0100 | |
changeset 18103 | 7a524bfa8d65 |
parent 18036 | d5d5ad4b78c5 |
child 18184 | 43c4589a9a78 |
permissions | -rw-r--r-- |
17225 | 1 |
(* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- *) |
16179 | 2 |
(* Title: Pure/IsaPlanner/term_lib.ML |
3 |
ID: $Id$ |
|
15481 | 4 |
Author: Lucas Dixon, University of Edinburgh |
5 |
lucasd@dai.ed.ac.uk |
|
6 |
Created: 17 Aug 2002 |
|
7 |
*) |
|
17225 | 8 |
(* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- *) |
15481 | 9 |
(* DESCRIPTION: |
10 |
||
11 |
Additional code to work with terms. |
|
12 |
||
17225 | 13 |
*) |
15481 | 14 |
(* -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- *) |
15 |
signature TERM_LIB = |
|
16 |
sig |
|
17225 | 17 |
val fo_term_height : term -> int |
18 |
val ho_term_height : term -> int |
|
15481 | 19 |
|
20 |
(* Matching/unification with exceptions handled *) |
|
17225 | 21 |
val clean_match : theory -> term * term |
22 |
-> ((indexname * (sort * typ)) list |
|
23 |
* (indexname * (typ * term)) list) option |
|
24 |
val clean_unify : theory -> int -> term * term |
|
25 |
-> ((indexname * (sort * typ)) list |
|
26 |
* (indexname * (typ * term)) list) Seq.seq |
|
15481 | 27 |
|
28 |
(* managing variables in terms, can doing conversions *) |
|
17225 | 29 |
val bounds_to_frees : term -> term |
15481 | 30 |
val bounds_to_frees_with_vars : |
17225 | 31 |
(string * typ) list -> term -> term |
15481 | 32 |
|
17225 | 33 |
val change_bounds_to_frees : term -> term |
34 |
val change_frees_to_vars : term -> term |
|
35 |
val change_vars_to_frees : term -> term |
|
15481 | 36 |
val loose_bnds_to_frees : |
17225 | 37 |
(string * typ) list -> term -> term |
15481 | 38 |
|
39 |
(* make all variables named uniquely *) |
|
17225 | 40 |
val unique_namify : term -> term |
15481 | 41 |
|
17225 | 42 |
(* breasking up a term and putting it into a normal form |
15481 | 43 |
independent of internal term context *) |
17225 | 44 |
val cleaned_term_conc : term -> term |
45 |
val cleaned_term_parts : term -> term list * term |
|
46 |
val cterm_of_term : term -> cterm |
|
15481 | 47 |
|
48 |
(* terms of theorems and subgoals *) |
|
17225 | 49 |
val term_of_thm : thm -> term |
50 |
val get_prems_of_sg_term : term -> term list |
|
51 |
val triv_thm_from_string : string -> thm |
|
15481 | 52 |
|
53 |
(* some common term manipulations *) |
|
17225 | 54 |
val try_dest_Trueprop : term -> term |
15481 | 55 |
|
17225 | 56 |
val bot_left_leaf_of : term -> term |
57 |
val bot_left_leaf_noabs_of : term -> term |
|
15481 | 58 |
|
59 |
(* term containing another term - an embedding check *) |
|
17225 | 60 |
val term_contains : term -> term -> bool |
15481 | 61 |
|
62 |
(* name-convertable checking - like ae-convertable, but allows for |
|
63 |
var's and free's to be mixed - and doesn't used buggy code. :-) *) |
|
17225 | 64 |
val get_name_eq_member : term -> term list -> term option |
65 |
val name_eq_member : term -> term list -> bool |
|
15481 | 66 |
val term_name_eq : |
17225 | 67 |
term -> |
68 |
term -> |
|
69 |
(term * term) list -> |
|
70 |
(term * term) list option |
|
15481 | 71 |
|
72 |
(* is the typ a function or is it atomic *) |
|
17225 | 73 |
val is_fun_typ : typ -> bool |
74 |
val is_atomic_typ : typ -> bool |
|
15481 | 75 |
|
76 |
(* variable analysis *) |
|
17225 | 77 |
val is_some_kind_of_var : term -> bool |
15481 | 78 |
val same_var_check : |
15531 | 79 |
''a -> ''b -> (''a * ''b) list -> (''a * ''b) list option |
17225 | 80 |
val has_new_vars : term * term -> bool |
81 |
val has_new_typ_vars : term * term -> bool |
|
15481 | 82 |
(* checks to see if the lhs -> rhs is a invalid rewrite rule *) |
17225 | 83 |
val is_not_valid_rwrule : theory -> (term * term) -> bool |
15481 | 84 |
|
85 |
(* get the frees in a term that are of atomic type, ie non-functions *) |
|
17225 | 86 |
val atomic_frees_of_term : term -> (string * typ) list |
15481 | 87 |
|
15814
d65f461c8672
lucas - fixed a big with renaming of bound variables. Other small changes.
dixon
parents:
15798
diff
changeset
|
88 |
(* get used names in a theorem to avoid upon instantiation. *) |
17225 | 89 |
val usednames_of_term : term -> string list |
90 |
val usednames_of_thm : thm -> string list |
|
15814
d65f461c8672
lucas - fixed a big with renaming of bound variables. Other small changes.
dixon
parents:
15798
diff
changeset
|
91 |
|
15481 | 92 |
(* Isar term skolemisationm and unsolemisation *) |
93 |
(* I think this is written also in IsarRTechn and also in somewhere else *) |
|
17225 | 94 |
(* val skolemise_term : (string,typ) list -> term -> term *) |
95 |
val unskolemise_all_term : |
|
96 |
term -> |
|
97 |
(((string * typ) * string) list * term) |
|
15481 | 98 |
|
17225 | 99 |
(* given a string describing term then a string for its type, returns |
15481 | 100 |
read term *) |
17225 | 101 |
val readwty : string -> string -> term |
15481 | 102 |
|
103 |
(* pretty stuff *) |
|
17225 | 104 |
val print_term : term -> unit |
15481 | 105 |
val pretty_print_sort : string list -> string |
17225 | 106 |
val pretty_print_term : term -> string |
107 |
val pretty_print_type : typ -> string |
|
15481 | 108 |
val pretty_print_typelist : |
17225 | 109 |
typ list -> (typ -> string) -> string |
110 |
||
15814
d65f461c8672
lucas - fixed a big with renaming of bound variables. Other small changes.
dixon
parents:
15798
diff
changeset
|
111 |
(* for debugging: quickly get a string of a term w.r.t the_context() *) |
17225 | 112 |
val string_of_term : term -> string |
15481 | 113 |
|
15814
d65f461c8672
lucas - fixed a big with renaming of bound variables. Other small changes.
dixon
parents:
15798
diff
changeset
|
114 |
(* Pretty printing in a way that allows them to be parsed by ML. |
17225 | 115 |
these are perhaps redundent, check the standard basis |
15481 | 116 |
lib for generic versions for any datatype? *) |
117 |
val writesort : string list -> unit |
|
17225 | 118 |
val writeterm : term -> unit |
119 |
val writetype : typ -> unit |
|
15481 | 120 |
end |
121 |
||
122 |
||
17225 | 123 |
structure TermLib : TERM_LIB = |
15481 | 124 |
struct |
125 |
||
17225 | 126 |
(* Two kinds of depth measure for HOAS terms, a first order (flat) and a |
127 |
higher order one. |
|
128 |
Note: not stable of eta-contraction: embedding eta-expands term, |
|
15481 | 129 |
thus we assume eta-expanded *) |
17225 | 130 |
fun fo_term_height (a $ b) = |
17797 | 131 |
Int.max (1 + fo_term_height b, (fo_term_height a)) |
15481 | 132 |
| fo_term_height (Abs(_,_,t)) = fo_term_height t |
133 |
| fo_term_height _ = 0; |
|
17225 | 134 |
|
135 |
fun ho_term_height (a $ b) = |
|
17797 | 136 |
1 + (Int.max (ho_term_height b, ho_term_height a)) |
15481 | 137 |
| ho_term_height (Abs(_,_,t)) = ho_term_height t |
138 |
| ho_term_height _ = 0; |
|
139 |
||
15928
66b165ee016c
lucas - made clean unify smash unifiers so that when we get flex-flex constraints subst does not barf. Also added fix_vars_upto_idx to IsaND.
dixon
parents:
15915
diff
changeset
|
140 |
|
15481 | 141 |
(* Higher order matching with exception handled *) |
142 |
(* returns optional instantiation *) |
|
17225 | 143 |
fun clean_match thy (a as (pat, t)) = |
17203 | 144 |
let val (tyenv, tenv) = Pattern.match thy a |
15915
b0e8b37642a4
lucas - improved interface to isand.ML and cleaned up clean-unification code, and added some better comments.
dixon
parents:
15814
diff
changeset
|
145 |
in SOME (Vartab.dest tyenv, Vartab.dest tenv) |
15798
016f3be5a5ec
Adapted to new interface of instantiation and unification / matching functions.
berghofe
parents:
15570
diff
changeset
|
146 |
end handle Pattern.MATCH => NONE; |
15481 | 147 |
(* Higher order unification with exception handled, return the instantiations *) |
148 |
(* given Signature, max var index, pat, tgt *) |
|
149 |
(* returns Seq of instantiations *) |
|
17225 | 150 |
fun clean_unify sgn ix (a as (pat, tgt)) = |
151 |
let |
|
152 |
(* type info will be re-derived, maybe this can be cached |
|
15481 | 153 |
for efficiency? *) |
154 |
val pat_ty = Term.type_of pat; |
|
155 |
val tgt_ty = Term.type_of tgt; |
|
17225 | 156 |
(* is it OK to ignore the type instantiation info? |
15481 | 157 |
or should I be using it? *) |
17225 | 158 |
val typs_unify = |
16934 | 159 |
SOME (Sign.typ_unify sgn (pat_ty, tgt_ty) (Term.Vartab.empty, ix)) |
160 |
handle Type.TUNIFY => NONE; |
|
15481 | 161 |
in |
162 |
case typs_unify of |
|
15531 | 163 |
SOME (typinsttab, ix2) => |
17225 | 164 |
let |
165 |
(* is it right to throw away the flexes? |
|
15481 | 166 |
or should I be using them somehow? *) |
17225 | 167 |
fun mk_insts env = |
15915
b0e8b37642a4
lucas - improved interface to isand.ML and cleaned up clean-unification code, and added some better comments.
dixon
parents:
15814
diff
changeset
|
168 |
(Vartab.dest (Envir.type_env env), |
b0e8b37642a4
lucas - improved interface to isand.ML and cleaned up clean-unification code, and added some better comments.
dixon
parents:
15814
diff
changeset
|
169 |
Envir.alist_of env); |
17225 | 170 |
val initenv = Envir.Envir {asol = Vartab.empty, |
15481 | 171 |
iTs = typinsttab, maxidx = ix2}; |
15928
66b165ee016c
lucas - made clean unify smash unifiers so that when we get flex-flex constraints subst does not barf. Also added fix_vars_upto_idx to IsaND.
dixon
parents:
15915
diff
changeset
|
172 |
val useq = (Unify.smash_unifiers (sgn,initenv,[a])) |
66b165ee016c
lucas - made clean unify smash unifiers so that when we get flex-flex constraints subst does not barf. Also added fix_vars_upto_idx to IsaND.
dixon
parents:
15915
diff
changeset
|
173 |
handle UnequalLengths => Seq.empty |
66b165ee016c
lucas - made clean unify smash unifiers so that when we get flex-flex constraints subst does not barf. Also added fix_vars_upto_idx to IsaND.
dixon
parents:
15915
diff
changeset
|
174 |
| Term.TERM _ => Seq.empty; |
17225 | 175 |
fun clean_unify' useq () = |
176 |
(case (Seq.pull useq) of |
|
15531 | 177 |
NONE => NONE |
178 |
| SOME (h,t) => SOME (mk_insts h, Seq.make (clean_unify' t))) |
|
15570 | 179 |
handle UnequalLengths => NONE |
15531 | 180 |
| Term.TERM _ => NONE; |
15481 | 181 |
in |
182 |
(Seq.make (clean_unify' useq)) |
|
183 |
end |
|
15531 | 184 |
| NONE => Seq.empty |
15481 | 185 |
end; |
186 |
||
17225 | 187 |
fun asm_mk t = assume (cterm_of (the_context()) t); |
188 |
fun asm_read s = (Thm.assume (read_cterm (the_context()) (s,propT))); |
|
15481 | 189 |
|
190 |
||
191 |
(* more pretty printing code for Isabelle terms etc *) |
|
192 |
||
193 |
||
17225 | 194 |
(* pretty_print_typelist l f = print a typelist. |
15481 | 195 |
l = list of types to print : typ list |
196 |
f = function used to print a single type : typ -> string |
|
197 |
*) |
|
198 |
fun pretty_print_typelist [] f = "" |
|
199 |
| pretty_print_typelist [(h: typ)] (f : typ -> string) = (f h) |
|
17225 | 200 |
| pretty_print_typelist ((h: typ) :: t) (f : typ -> string) = |
15481 | 201 |
(f h) ^ ", " ^ (pretty_print_typelist t f); |
202 |
||
203 |
||
204 |
||
17225 | 205 |
(* pretty_print_sort s = print a sort |
15481 | 206 |
s = sort to print : string list |
207 |
*) |
|
208 |
fun pretty_print_sort [] = "" |
|
209 |
| pretty_print_sort ([h]) = "\"" ^ h ^ "\"" |
|
210 |
| pretty_print_sort (h :: t) = "\"" ^ h ^ "\"," ^ (pretty_print_sort t); |
|
211 |
||
212 |
||
213 |
(* pretty_print_type t = print a type |
|
214 |
t = type to print : type |
|
215 |
*) |
|
17225 | 216 |
fun pretty_print_type (Type (n, l)) = |
15481 | 217 |
"Type(\"" ^ n ^ "\", [" ^ (pretty_print_typelist l pretty_print_type) ^ "])" |
17225 | 218 |
| pretty_print_type (TFree (n, s)) = |
15481 | 219 |
"TFree(\"" ^ n ^ "\", [" ^ (pretty_print_sort s) ^ "])" |
17225 | 220 |
| pretty_print_type (TVar ((n, i), s)) = |
15481 | 221 |
"TVar( (\"" ^ n ^ "\", " ^ (string_of_int i) ^ "), [" ^ (pretty_print_sort s) ^ "])"; |
222 |
||
223 |
||
224 |
(* pretty_print_term t = print a term prints types and sorts too. |
|
225 |
t = term to print : term |
|
226 |
*) |
|
17225 | 227 |
fun pretty_print_term (Const (s, t)) = |
15481 | 228 |
"Const(\"" ^ s ^ "\", " ^ (pretty_print_type t) ^ ")" |
17225 | 229 |
| pretty_print_term (Free (s, t)) = |
15481 | 230 |
"Free(\"" ^ s ^ "\", " ^ (pretty_print_type t) ^ ")" |
17225 | 231 |
| pretty_print_term (Var ((n, i), t)) = |
15481 | 232 |
"Var( (\"" ^ n ^ "\"," ^ (string_of_int i) ^ "), " ^ (pretty_print_type t) ^ ")" |
17225 | 233 |
| pretty_print_term (Bound i) = |
15481 | 234 |
"Bound(" ^ (string_of_int i) ^ ")" |
17225 | 235 |
| pretty_print_term (Abs (s, t, r)) = |
15481 | 236 |
"Abs(\"" ^ s ^ "\"," ^ (pretty_print_type t) ^ ", \n " ^ (pretty_print_term r) ^ ")" |
17225 | 237 |
| pretty_print_term (op $ (t1, t2)) = |
15481 | 238 |
"(" ^ (pretty_print_term t1) ^ ") $\n (" ^ (pretty_print_term t2) ^ ")"; |
239 |
||
240 |
(* Write the term out nicly instead of just creating a string for it *) |
|
241 |
fun writeterm t = writeln (pretty_print_term t); |
|
242 |
fun writetype t = writeln (pretty_print_type t); |
|
243 |
fun writesort s = writeln (pretty_print_sort s); |
|
244 |
||
17225 | 245 |
fun cterm_of_term (t : term) = Thm.cterm_of (the_context()) t; |
15481 | 246 |
fun term_of_thm t = (Thm.prop_of t); |
247 |
||
17225 | 248 |
fun string_of_term t = Sign.string_of_term (the_context()) t; |
16857
6389511d4609
lucas - slightly cleaned up. Removed redudent copy of Symtab structure.
dixon
parents:
16179
diff
changeset
|
249 |
fun print_term t = writeln (string_of_term t); |
15481 | 250 |
|
17931 | 251 |
(* create a trivial thm from anything... *) |
252 |
fun triv_thm_from_string s = |
|
253 |
let val thy = the_context() |
|
254 |
in Thm.trivial (cterm_of thy (Sign.read_prop thy s)) end; |
|
15481 | 255 |
|
256 |
(* Checks if vars could be the same - alpha convertable |
|
257 |
w.r.t. previous vars, a and b are assumed to be vars, |
|
258 |
free vars, but not bound vars, |
|
259 |
Note frees and vars must all have unique names. *) |
|
260 |
fun same_var_check a b L = |
|
17225 | 261 |
let |
15531 | 262 |
fun bterm_from t [] = NONE |
17225 | 263 |
| bterm_from t ((a,b)::m) = |
15531 | 264 |
if t = a then SOME b else bterm_from t m |
15481 | 265 |
|
266 |
val bl_opt = bterm_from a L |
|
267 |
in |
|
268 |
case bterm_from a L of |
|
15531 | 269 |
NONE => SOME ((a,b)::L) |
270 |
| SOME b2 => if b2 = b then SOME L else NONE |
|
15481 | 271 |
end; |
272 |
||
273 |
(* FIXME: make more efficient, only require a single new var! *) |
|
274 |
(* check if the new term has any meta variables not in the old term *) |
|
17225 | 275 |
fun has_new_vars (old, new) = |
276 |
(case IsaPLib.lrem (op =) (Term.term_vars old) (Term.term_vars new) of |
|
15481 | 277 |
[] => false |
278 |
| (_::_) => true); |
|
279 |
(* check if the new term has any meta variables not in the old term *) |
|
17225 | 280 |
fun has_new_typ_vars (old, new) = |
281 |
(case IsaPLib.lrem (op =) (Term.term_tvars old) (Term.term_tvars new) of |
|
15481 | 282 |
[] => false |
283 |
| (_::_) => true); |
|
284 |
||
15570 | 285 |
(* This version avoids name conflicts that might be introduced by |
15481 | 286 |
unskolemisation, and returns a list of (string * Term.typ) * string, |
287 |
where the outer string is the original name, and the inner string is |
|
288 |
the new name, and the type is the type of the free variable that was |
|
289 |
renamed. *) |
|
290 |
local |
|
17225 | 291 |
fun myadd (n,ty) (L as (renames, names)) = |
292 |
let val n' = Syntax.dest_skolem n in |
|
293 |
case (Library.find_first (fn (_,n2) => (n2 = n)) renames) of |
|
294 |
NONE => |
|
295 |
let val renamedn = Term.variant names n' in |
|
296 |
(renamedn, (((renamedn, ty), n) :: renames, |
|
15481 | 297 |
renamedn :: names)) end |
15531 | 298 |
| (SOME ((renamedn, _), _)) => (renamedn, L) |
15481 | 299 |
end |
15570 | 300 |
handle Fail _ => (n, L); |
15481 | 301 |
|
17225 | 302 |
fun unsk (L,f) (t1 $ t2) = |
303 |
let val (L', t1') = unsk (L, I) t1 |
|
15481 | 304 |
in unsk (L', (fn x => f (t1' $ x))) t2 end |
17225 | 305 |
| unsk (L,f) (Abs(n,ty,t)) = |
15481 | 306 |
unsk (L, (fn x => Abs(n,ty,x))) t |
17225 | 307 |
| unsk (L, f) (Free (n,ty)) = |
15481 | 308 |
let val (renamed_n, L') = myadd (n ,ty) L |
309 |
in (L', f (Free (renamed_n, ty))) end |
|
310 |
| unsk (L, f) l = (L, f l); |
|
311 |
in |
|
17225 | 312 |
fun unskolemise_all_term t = |
313 |
let |
|
314 |
val names = Term.add_term_names (t,[]) |
|
15481 | 315 |
val ((renames,names'),t') = unsk (([], names),I) t |
316 |
in (renames,t') end; |
|
317 |
end |
|
318 |
||
319 |
(* true if the type t is a function *) |
|
17225 | 320 |
fun is_fun_typ (Type(s, l)) = |
15481 | 321 |
if s = "fun" then true else false |
322 |
| is_fun_typ _ = false; |
|
323 |
||
324 |
val is_atomic_typ = not o is_fun_typ; |
|
325 |
||
326 |
(* get the frees in a term that are of atomic type, ie non-functions *) |
|
327 |
val atomic_frees_of_term = |
|
17225 | 328 |
List.filter (is_atomic_typ o snd) |
329 |
o map Term.dest_Free |
|
15481 | 330 |
o Term.term_frees; |
331 |
||
15814
d65f461c8672
lucas - fixed a big with renaming of bound variables. Other small changes.
dixon
parents:
15798
diff
changeset
|
332 |
fun usednames_of_term t = Term.add_term_names (t,[]); |
17225 | 333 |
fun usednames_of_thm th = |
15814
d65f461c8672
lucas - fixed a big with renaming of bound variables. Other small changes.
dixon
parents:
15798
diff
changeset
|
334 |
let val rep = Thm.rep_thm th |
d65f461c8672
lucas - fixed a big with renaming of bound variables. Other small changes.
dixon
parents:
15798
diff
changeset
|
335 |
val hyps = #hyps rep |
d65f461c8672
lucas - fixed a big with renaming of bound variables. Other small changes.
dixon
parents:
15798
diff
changeset
|
336 |
val (tpairl,tpairr) = Library.split_list (#tpairs rep) |
17225 | 337 |
val prop = #prop rep |
15814
d65f461c8672
lucas - fixed a big with renaming of bound variables. Other small changes.
dixon
parents:
15798
diff
changeset
|
338 |
in |
d65f461c8672
lucas - fixed a big with renaming of bound variables. Other small changes.
dixon
parents:
15798
diff
changeset
|
339 |
List.foldr Term.add_term_names [] (prop :: (tpairl @ (tpairr @ hyps))) |
d65f461c8672
lucas - fixed a big with renaming of bound variables. Other small changes.
dixon
parents:
15798
diff
changeset
|
340 |
end; |
15481 | 341 |
|
17225 | 342 |
(* read in a string and a top-level type and this will give back a term *) |
343 |
fun readwty tstr tystr = |
|
344 |
let val thy = the_context() |
|
345 |
in Sign.simple_read_term thy (Sign.read_typ (thy, K NONE) tystr) tstr end; |
|
15481 | 346 |
|
347 |
(* first term is equal to the second in some name convertable |
|
348 |
way... Note: This differs from the aeconv in the Term.ML file of |
|
17225 | 349 |
Isabelle in that it allows a var to be alpha-equiv to a free var. |
350 |
||
15481 | 351 |
Also, the isabelle term.ML version of aeconv uses a |
352 |
function that it claims doesn't work! *) |
|
17225 | 353 |
fun term_name_eq (Abs(_,ty1,t1)) (Abs(_,ty2,t2)) l = |
15481 | 354 |
if ty1 = ty2 then term_name_eq t1 t2 l |
15531 | 355 |
else NONE |
15481 | 356 |
| term_name_eq (ah $ at) (bh $ bt) l = |
17225 | 357 |
let |
15481 | 358 |
val lopt = (term_name_eq ah bh l) |
359 |
in |
|
17225 | 360 |
if isSome lopt then |
16857
6389511d4609
lucas - slightly cleaned up. Removed redudent copy of Symtab structure.
dixon
parents:
16179
diff
changeset
|
361 |
term_name_eq at bt (valOf lopt) |
15481 | 362 |
else |
15531 | 363 |
NONE |
15481 | 364 |
end |
17225 | 365 |
| term_name_eq (Const(a,T)) (Const(b,U)) l = |
15531 | 366 |
if a=b andalso T=U then SOME l |
367 |
else NONE |
|
17225 | 368 |
| term_name_eq (a as Free(s1,ty1)) (b as Free(s2,ty2)) l = |
15481 | 369 |
same_var_check a b l |
17225 | 370 |
| term_name_eq (a as Free(s1,ty1)) (b as Var(n2,ty2)) l = |
15481 | 371 |
same_var_check a b l |
17225 | 372 |
| term_name_eq (a as Var(n1,ty1)) (b as Free(s2,ty2)) l = |
15481 | 373 |
same_var_check a b l |
17225 | 374 |
| term_name_eq (a as Var(n1,ty1)) (b as Var(n2,ty2)) l = |
15481 | 375 |
same_var_check a b l |
17225 | 376 |
| term_name_eq (Bound i) (Bound j) l = |
15531 | 377 |
if i = j then SOME l else NONE |
378 |
| term_name_eq a b l = ((*writeln ("unchecked case:\n" ^ "a:\n" ^ (pretty_print_term a) ^ "\nb:\n" ^ (pretty_print_term b));*) NONE); |
|
15481 | 379 |
|
380 |
(* checks to see if the term in a name-equivalent member of the list of terms. *) |
|
15531 | 381 |
fun get_name_eq_member a [] = NONE |
17225 | 382 |
| get_name_eq_member a (h :: t) = |
383 |
if isSome (term_name_eq a h []) then SOME h |
|
15481 | 384 |
else get_name_eq_member a t; |
385 |
||
386 |
fun name_eq_member a [] = false |
|
17225 | 387 |
| name_eq_member a (h :: t) = |
388 |
if isSome (term_name_eq a h []) then true |
|
15481 | 389 |
else name_eq_member a t; |
390 |
||
391 |
(* true if term is a variable *) |
|
392 |
fun is_some_kind_of_var (Free(s, ty)) = true |
|
393 |
| is_some_kind_of_var (Var(i, ty)) = true |
|
394 |
| is_some_kind_of_var (Bound(i)) = true |
|
395 |
| is_some_kind_of_var _ = false; |
|
396 |
||
397 |
(* checks to see if the lhs -> rhs is a invalid rewrite rule *) |
|
398 |
(* FIXME: we should really check that there is a subterm on the lhs |
|
399 |
which embeds into the rhs, this would be much closer to the normal |
|
400 |
notion of valid wave rule - ie there exists at least one case where it |
|
15814
d65f461c8672
lucas - fixed a big with renaming of bound variables. Other small changes.
dixon
parents:
15798
diff
changeset
|
401 |
is a valid wave rule... *) |
17225 | 402 |
fun is_not_valid_rwrule thy (lhs, rhs) = |
15814
d65f461c8672
lucas - fixed a big with renaming of bound variables. Other small changes.
dixon
parents:
15798
diff
changeset
|
403 |
Term.is_Var (Term.head_of lhs) (* if lhs is essentially just a var *) |
17225 | 404 |
orelse has_new_vars (lhs,rhs) |
405 |
orelse has_new_typ_vars (lhs,rhs) |
|
17203 | 406 |
orelse Pattern.matches_subterm thy (lhs, rhs); |
15481 | 407 |
|
408 |
||
409 |
(* first term contains the second in some name convertable way... *) |
|
410 |
(* note: this is equivalent to an alpha-convertable emedding *) |
|
411 |
(* takes as args: term containing a, term contained b, |
|
17225 | 412 |
(bound vars of a, bound vars of b), |
413 |
current alpha-conversion-pairs, |
|
15481 | 414 |
returns: bool:can convert, new alpha-conversion table *) |
415 |
(* in bellow: we *don't* use: a loose notion that only requires |
|
416 |
variables to match variables, and doesn't worry about the actual |
|
417 |
pattern in the variables. *) |
|
17225 | 418 |
fun term_contains1 (Bs, FVs) (Abs(s,ty,t)) (Abs(s2,ty2,t2)) = |
419 |
if ty = ty2 then |
|
15531 | 420 |
term_contains1 ((SOME(s,s2,ty)::Bs), FVs) t t2 |
15481 | 421 |
else [] |
422 |
||
423 |
| term_contains1 T t1 (Abs(s2,ty2,t2)) = [] |
|
424 |
||
17225 | 425 |
| term_contains1 (Bs, FVs) (Abs(s,ty,t)) t2 = |
15531 | 426 |
term_contains1 (NONE::Bs, FVs) t t2 |
15481 | 427 |
|
428 |
| term_contains1 T (ah $ at) (bh $ bt) = |
|
17225 | 429 |
(term_contains1 T ah (bh $ bt)) @ |
15481 | 430 |
(term_contains1 T at (bh $ bt)) @ |
17225 | 431 |
(List.concat (map (fn inT => (term_contains1 inT at bt)) |
15481 | 432 |
(term_contains1 T ah bh))) |
433 |
||
434 |
| term_contains1 T a (bh $ bt) = [] |
|
435 |
||
436 |
| term_contains1 T (ah $ at) b = |
|
437 |
(term_contains1 T ah b) @ (term_contains1 T at b) |
|
438 |
||
17225 | 439 |
| term_contains1 T a b = |
15481 | 440 |
(* simple list table lookup to check if a named variable has been |
441 |
mapped to a variable, if not adds the mapping and return some new |
|
442 |
list mapping, if it is then it checks that the pair are mapped to |
|
443 |
each other, if so returns the current mapping list, else none. *) |
|
17225 | 444 |
let |
15531 | 445 |
fun bterm_from t [] = NONE |
17225 | 446 |
| bterm_from t ((a,b)::m) = |
15531 | 447 |
if t = a then SOME b else bterm_from t m |
15481 | 448 |
|
449 |
(* check to see if, w.r.t. the variable mapping, two terms are leaf |
|
450 |
terms and are mapped to each other. Note constants are only mapped |
|
17225 | 451 |
to the same constant. *) |
15481 | 452 |
fun same_leaf_check (T as (Bs,FVs)) (Bound i) (Bound j) = |
17225 | 453 |
let |
15481 | 454 |
fun aux_chk (i1,i2) [] = false |
15531 | 455 |
| aux_chk (0,0) ((SOME _) :: bnds) = true |
456 |
| aux_chk (i1,0) (NONE :: bnds) = false |
|
457 |
| aux_chk (i1,i2) ((SOME _) :: bnds) = |
|
15481 | 458 |
aux_chk (i1 - 1,i2 - 1) bnds |
15531 | 459 |
| aux_chk (i1,i2) (NONE :: bnds) = |
17225 | 460 |
aux_chk (i1,i2 - 1) bnds |
15481 | 461 |
in |
462 |
if (aux_chk (i,j) Bs) then [T] |
|
463 |
else [] |
|
464 |
end |
|
17225 | 465 |
| same_leaf_check (T as (Bs,(Fs,Vs))) |
466 |
(a as (Free (an,aty))) |
|
15481 | 467 |
(b as (Free (bn,bty))) = |
17225 | 468 |
(case bterm_from an Fs of |
15531 | 469 |
SOME b2n => if bn = b2n then [T] |
15481 | 470 |
else [] (* conflict of var name *) |
15531 | 471 |
| NONE => [(Bs,((an,bn)::Fs,Vs))]) |
17225 | 472 |
| same_leaf_check (T as (Bs,(Fs,Vs))) |
473 |
(a as (Var (an,aty))) |
|
15481 | 474 |
(b as (Var (bn,bty))) = |
17225 | 475 |
(case bterm_from an Vs of |
15531 | 476 |
SOME b2n => if bn = b2n then [T] |
15481 | 477 |
else [] (* conflict of var name *) |
15531 | 478 |
| NONE => [(Bs,(Fs,(an,bn)::Vs))]) |
15481 | 479 |
| same_leaf_check T (a as (Const _)) (b as (Const _)) = |
480 |
if a = b then [T] else [] |
|
481 |
| same_leaf_check T _ _ = [] |
|
482 |
||
483 |
in |
|
484 |
same_leaf_check T a b |
|
485 |
end; |
|
486 |
||
487 |
(* wrapper for term_contains1: checks if the term "a" contains in |
|
488 |
some embedded way, (w.r.t. name -convertable) the term "b" *) |
|
17225 | 489 |
fun term_contains a b = |
15481 | 490 |
case term_contains1 ([],([],[])) a b of |
491 |
(_ :: _) => true |
|
492 |
| [] => false; |
|
493 |
||
494 |
(* change all bound variables to see ones with appropriate name and |
|
495 |
type *) |
|
496 |
(* naming convention is OK as we use 'variant' from term.ML *) |
|
497 |
(* Note "bounds_to_frees" defined below, its better and quicker, but |
|
498 |
keeps the quantifiers handing about, and changes all bounds, not |
|
499 |
just universally quantified ones. *) |
|
17225 | 500 |
fun change_bounds_to_frees t = |
501 |
let |
|
15481 | 502 |
val vars = strip_all_vars t |
503 |
val frees_names = map (fn Free(s,n) => s | _ => "") (term_frees t) |
|
504 |
val body = strip_all_body t |
|
505 |
||
506 |
fun bnds_to_frees [] _ acc = acc |
|
17225 | 507 |
| bnds_to_frees ((name,ty)::more) names acc = |
508 |
let |
|
15481 | 509 |
val new_name = variant names name |
510 |
in |
|
511 |
bnds_to_frees more (new_name::names) (Free(new_name,ty)::acc) |
|
512 |
end |
|
513 |
in |
|
514 |
(subst_bounds ((bnds_to_frees vars frees_names []), body)) |
|
17225 | 515 |
end; |
15481 | 516 |
|
517 |
(* a runtime-quick function which makes sure that every variable has a |
|
518 |
unique name *) |
|
17225 | 519 |
fun unique_namify_aux (ntab,(Abs(s,ty,t))) = |
17412 | 520 |
(case Symtab.lookup ntab s of |
17225 | 521 |
NONE => |
522 |
let |
|
17412 | 523 |
val (ntab2,t2) = unique_namify_aux (Symtab.update (s, s) ntab, t) |
15481 | 524 |
in |
17225 | 525 |
(ntab2,Abs(s,ty,t2)) |
15481 | 526 |
end |
17225 | 527 |
| SOME s2 => |
528 |
let |
|
529 |
val s_new = (Term.variant (Symtab.keys ntab) s) |
|
530 |
val (ntab2,t2) = |
|
17412 | 531 |
unique_namify_aux (Symtab.update (s_new, s_new) ntab, t) |
15481 | 532 |
in |
17225 | 533 |
(ntab2,Abs(s_new,ty,t2)) |
15481 | 534 |
end) |
17225 | 535 |
| unique_namify_aux (ntab,(a $ b)) = |
536 |
let |
|
15481 | 537 |
val (ntab1,t1) = unique_namify_aux (ntab,a) |
17225 | 538 |
val (ntab2,t2) = unique_namify_aux (ntab1,b) |
15481 | 539 |
in |
540 |
(ntab2, t1$t2) |
|
541 |
end |
|
542 |
| unique_namify_aux (nt as (ntab,Const x)) = nt |
|
17225 | 543 |
| unique_namify_aux (nt as (ntab,f as Free (s,ty))) = |
17412 | 544 |
(case Symtab.lookup ntab s of |
545 |
NONE => (Symtab.update (s, s) ntab, f) |
|
15531 | 546 |
| SOME _ => nt) |
17225 | 547 |
| unique_namify_aux (nt as (ntab,v as Var ((s,i),ty))) = |
17412 | 548 |
(case Symtab.lookup ntab s of |
549 |
NONE => (Symtab.update (s, s) ntab, v) |
|
15531 | 550 |
| SOME _ => nt) |
15481 | 551 |
| unique_namify_aux (nt as (ntab, Bound i)) = nt; |
552 |
||
17225 | 553 |
fun unique_namify t = |
16857
6389511d4609
lucas - slightly cleaned up. Removed redudent copy of Symtab structure.
dixon
parents:
16179
diff
changeset
|
554 |
#2 (unique_namify_aux (Symtab.empty, t)); |
15481 | 555 |
|
556 |
(* a runtime-quick function which makes sure that every variable has a |
|
557 |
unique name and also changes bound variables to free variables, used |
|
558 |
for embedding checks, Note that this is a pretty naughty term |
|
559 |
manipulation, which doesn't have necessary relation to the original |
|
560 |
sematics of the term. This is really a trick for our embedding code. *) |
|
561 |
||
17225 | 562 |
fun bounds_to_frees_aux T (ntab,(Abs(s,ty,t))) = |
17412 | 563 |
(case Symtab.lookup ntab s of |
17225 | 564 |
NONE => |
565 |
let |
|
566 |
val (ntab2,t2) = |
|
17412 | 567 |
bounds_to_frees_aux ((s,ty)::T) (Symtab.update (s, s) ntab, t) |
15481 | 568 |
in |
569 |
(ntab2,Abs(s,ty,t2)) |
|
570 |
end |
|
17225 | 571 |
| SOME s2 => |
572 |
let |
|
16857
6389511d4609
lucas - slightly cleaned up. Removed redudent copy of Symtab structure.
dixon
parents:
16179
diff
changeset
|
573 |
val s_new = (Term.variant (Symtab.keys ntab) s) |
17225 | 574 |
val (ntab2,t2) = |
575 |
bounds_to_frees_aux ((s_new,ty)::T) |
|
17412 | 576 |
(Symtab.update (s_new, s_new) ntab, t) |
15481 | 577 |
in |
578 |
(ntab2,Abs(s_new,ty,t2)) |
|
579 |
end) |
|
17225 | 580 |
| bounds_to_frees_aux T (ntab,(a $ b)) = |
581 |
let |
|
15481 | 582 |
val (ntab1,t1) = bounds_to_frees_aux T (ntab,a) |
17225 | 583 |
val (ntab2,t2) = bounds_to_frees_aux T (ntab1,b) |
15481 | 584 |
in |
585 |
(ntab2, t1$t2) |
|
586 |
end |
|
587 |
| bounds_to_frees_aux T (nt as (ntab,Const x)) = nt |
|
17225 | 588 |
| bounds_to_frees_aux T (nt as (ntab,f as Free (s,ty))) = |
17412 | 589 |
(case Symtab.lookup ntab s of |
590 |
NONE => (Symtab.update (s, s) ntab, f) |
|
15531 | 591 |
| SOME _ => nt) |
17225 | 592 |
| bounds_to_frees_aux T (nt as (ntab,v as Var ((s,i),ty))) = |
17412 | 593 |
(case Symtab.lookup ntab s of |
594 |
NONE => (Symtab.update (s, s) ntab, v) |
|
15531 | 595 |
| SOME _ => nt) |
17225 | 596 |
| bounds_to_frees_aux T (nt as (ntab, Bound i)) = |
597 |
let |
|
598 |
val (s,ty) = List.nth (T,i) |
|
15481 | 599 |
in |
600 |
(ntab, Free (s,ty)) |
|
601 |
end; |
|
602 |
||
603 |
||
17225 | 604 |
fun bounds_to_frees t = |
16857
6389511d4609
lucas - slightly cleaned up. Removed redudent copy of Symtab structure.
dixon
parents:
16179
diff
changeset
|
605 |
#2 (bounds_to_frees_aux [] (Symtab.empty,t)); |
15481 | 606 |
|
17225 | 607 |
fun bounds_to_frees_with_vars vars t = |
16857
6389511d4609
lucas - slightly cleaned up. Removed redudent copy of Symtab structure.
dixon
parents:
16179
diff
changeset
|
608 |
#2 (bounds_to_frees_aux vars (Symtab.empty,t)); |
15481 | 609 |
|
610 |
||
611 |
||
612 |
(* loose bounds to frees *) |
|
17225 | 613 |
fun loose_bnds_to_frees_aux (bnds,vars) (Abs(s,ty,t)) = |
15481 | 614 |
Abs(s,ty,loose_bnds_to_frees_aux (bnds + 1,vars) t) |
17225 | 615 |
| loose_bnds_to_frees_aux (bnds,vars) (a $ b) = |
616 |
(loose_bnds_to_frees_aux (bnds,vars) a) |
|
15481 | 617 |
$ (loose_bnds_to_frees_aux (bnds,vars) b) |
17225 | 618 |
| loose_bnds_to_frees_aux (bnds,vars) (t as (Bound i)) = |
15570 | 619 |
if (bnds <= i) then Free (List.nth (vars,i - bnds)) |
15481 | 620 |
else t |
621 |
| loose_bnds_to_frees_aux (bnds,vars) t = t; |
|
622 |
||
623 |
||
17225 | 624 |
fun loose_bnds_to_frees vars t = |
15481 | 625 |
loose_bnds_to_frees_aux (0,vars) t; |
626 |
||
627 |
||
18036 | 628 |
(* FIXME ObjectLogic.drop_judgment *) |
15481 | 629 |
fun try_dest_Trueprop (Const("Trueprop", _) $ T) = T |
17225 | 630 |
| try_dest_Trueprop T = T; |
15481 | 631 |
|
632 |
fun bot_left_leaf_of (l $ r) = bot_left_leaf_of l |
|
633 |
| bot_left_leaf_of (Abs(s,ty,t)) = bot_left_leaf_of t |
|
634 |
| bot_left_leaf_of x = x; |
|
635 |
||
15814
d65f461c8672
lucas - fixed a big with renaming of bound variables. Other small changes.
dixon
parents:
15798
diff
changeset
|
636 |
fun bot_left_leaf_noabs_of (l $ r) = bot_left_leaf_noabs_of l |
d65f461c8672
lucas - fixed a big with renaming of bound variables. Other small changes.
dixon
parents:
15798
diff
changeset
|
637 |
| bot_left_leaf_noabs_of x = x; |
15481 | 638 |
|
639 |
(* cleaned up normal form version of the subgoal terms conclusion *) |
|
17225 | 640 |
fun cleaned_term_conc t = |
15481 | 641 |
let |
642 |
val concl = Logic.strip_imp_concl (change_bounds_to_frees t) |
|
17225 | 643 |
in |
18036 | 644 |
(try_dest_Trueprop (Logic.unprotect concl handle TERM _ => concl)) |
15481 | 645 |
end; |
646 |
||
17225 | 647 |
(* fun get_prems_of_sg_term t = |
15481 | 648 |
map opt_dest_Trueprop (Logic.strip_imp_prems t); *) |
649 |
||
17225 | 650 |
fun get_prems_of_sg_term t = |
15481 | 651 |
map try_dest_Trueprop (Logic.strip_assums_hyp t); |
652 |
||
653 |
||
18036 | 654 |
(* drop premises, clean bound var stuff, and make a trueprop... *) |
17225 | 655 |
fun cleaned_term_parts t = |
656 |
let |
|
15481 | 657 |
val t2 = (change_bounds_to_frees t) |
658 |
val concl = Logic.strip_imp_concl t2 |
|
659 |
val prems = map try_dest_Trueprop (Logic.strip_imp_prems t2) |
|
17225 | 660 |
in |
18036 | 661 |
(prems, (try_dest_Trueprop ((Logic.unprotect concl handle TERM _ => concl)))) |
15481 | 662 |
end; |
663 |
||
664 |
(* change free variables to vars and visa versa *) |
|
665 |
(* *** check naming is OK, can we just use the vasr old name? *) |
|
666 |
(* *** Check: Logic.varify and Logic.unvarify *) |
|
17225 | 667 |
fun change_vars_to_frees (a$b) = |
15481 | 668 |
(change_vars_to_frees a) $ (change_vars_to_frees b) |
17225 | 669 |
| change_vars_to_frees (Abs(s,ty,t)) = |
15481 | 670 |
(Abs(s,Type.varifyT ty,change_vars_to_frees t)) |
671 |
| change_vars_to_frees (Var((s,i),ty)) = (Free(s,Type.unvarifyT ty)) |
|
672 |
| change_vars_to_frees l = l; |
|
673 |
||
17225 | 674 |
fun change_frees_to_vars (a$b) = |
15481 | 675 |
(change_frees_to_vars a) $ (change_frees_to_vars b) |
17225 | 676 |
| change_frees_to_vars (Abs(s,ty,t)) = |
15481 | 677 |
(Abs(s,Type.varifyT ty,change_frees_to_vars t)) |
678 |
| change_frees_to_vars (Free(s,ty)) = (Var((s,0),Type.varifyT ty)) |
|
679 |
| change_frees_to_vars l = l; |
|
680 |
||
681 |
||
16934 | 682 |
end; |