1structure Term :> Term = 2struct 3 4open Feedback Lib KernelTypes Type 5 6val kernelid = "expknl" 7 8infixr --> |-> 9 10val ERR = mk_HOL_ERR "Term" 11val WARN = HOL_WARNING "Term" 12 13(* used internally to avoid term rebuilding during substitution and 14 type instantiation *) 15exception Unchanged 16 17fun qcomb2 con (f, g) (x, y) = 18 let val fx = f x 19 in 20 let val gy = g y 21 in 22 con (fx, gy) 23 end handle Unchanged => con (fx, y) 24 end handle Unchanged => let val gy = g y in con (x, gy) end 25 26(* apply a function f under "constructor" con, handling Unchanged *) 27fun qcomb con f = qcomb2 con (f, f) 28 29type 'a set = 'a HOLset.set 30 31val compare_key = KernelSig.name_compare 32val compare_cinfo = KernelSig.id_compare 33 34val c2string = KernelSig.id_toString 35val id2string = KernelSig.name_toString 36 37val const_table = KernelSig.new_table() 38 39fun prim_delete_const kn = ignore (KernelSig.retire_name(const_table, kn)) 40 41fun inST s = not (null (KernelSig.listName const_table s)) 42 43fun prim_new_const (k as {Thy,Name}) ty = let 44 val id = KernelSig.insert(const_table, k, ty) 45in 46 Const(id, ty) 47end 48 49fun uptodate_term tm = let 50 fun recurse tmlist = 51 case tmlist of 52 [] => true 53 | tm :: rest => let 54 in 55 case tm of 56 Var(s, ty) => uptodate_type ty andalso recurse rest 57 | Const(info, ty) => KernelSig.uptodate_id info andalso 58 uptodate_type ty andalso 59 recurse rest 60 | App(f, x) => recurse (f::x::rest) 61 | Abs(v, body) => recurse (v::body::rest) 62 end 63in 64 recurse [tm] 65end 66 67fun thy_consts s = let 68 fun f (k, info, acc) = 69 if #Thy k = s then Const info :: acc 70 else acc 71in 72 KernelSig.foldl f [] const_table 73end 74 75fun del_segment s = KernelSig.del_segment(const_table, s) 76 77fun prim_decls s = KernelSig.listName const_table s 78 79fun decls s = let 80 fun foldthis (k,v,acc) = 81 if #Name k = s then Const v::acc else acc 82in 83 KernelSig.foldl foldthis [] const_table 84end 85 86fun all_consts () = let 87 fun foldthis (_,v,acc) = Const v :: acc 88in 89 KernelSig.foldl foldthis [] const_table 90end 91 92 93fun type_of t = let 94 fun ty_of t k = 95 case t of 96 Var(_, ty) => k ty 97 | App(t1, t2) => ty_of t1 (fn ty => k (#2 (dom_rng ty))) 98 | Const(_, ty) => k ty 99 | Abs(Var(_, ty1), t) => ty_of t (fn tty => k (ty1 --> tty)) 100 | _ => raise Fail "Catastrophic invariant failure" 101in 102 ty_of t Lib.I 103end 104 105 106(* discriminators *) 107fun is_var (Var _) = true | is_var _ = false 108fun is_const (Const _) = true | is_const _ = false 109fun is_abs (Abs _) = true | is_abs _ = false 110fun is_comb (App _) = true | is_comb _ = false 111 112fun same_const t1 t2 = 113 case (t1, t2) of 114 (Const(r1, _), Const(r2, _)) => r1 = r2 115 | _ => false 116 117(* constructors - variables *) 118val mk_var = Var 119fun mk_primed_var (Name,Ty) = 120 let val next = Lexis.nameStrm Name 121 fun spin s = if inST s then spin (next()) else s 122 in mk_var(spin Name, Ty) 123 end; 124 125local val genvar_prefix = "%%genvar%%" 126 fun num2name i = genvar_prefix^Lib.int_to_string i 127 val nameStrm = Lib.mk_istream (fn x => x+1) 0 num2name 128in 129fun genvar ty = Var(state(next nameStrm), ty) 130 131fun genvars ty = 132 let fun gen acc n = if n <= 0 then rev acc else gen (genvar ty::acc) (n-1) 133 in gen [] 134 end 135 136fun is_genvar (Var(Name,_)) = String.isPrefix genvar_prefix Name 137 | is_genvar _ = false; 138end; 139 140(* constructors - constants *) 141fun mk_const(s, ty) = 142 case prim_decls s of 143 [] => raise ERR "mk_const" ("No constant with name "^s) 144 | [(_, (id,basety))] => if can (match_type basety) ty then 145 Const (id, ty) 146 else raise ERR "mk_const" 147 ("Not a type instance: "^c2string id) 148 | (_, (id,basety))::_ => 149 if can (match_type basety) ty then 150 (WARN "mk_const" (s^": more than one possibility"); Const (id,ty)) 151 else raise ERR "mk_const" ("Not a type instance: "^ c2string id) 152 153fun prim_mk_const (k as {Thy, Name}) = 154 case KernelSig.peek(const_table, k) of 155 NONE => raise ERR "prim_mk_const" ("No such constant: "^id2string k) 156 | SOME x => Const x 157 158fun mk_thy_const {Thy,Name,Ty} = let 159 val k = {Thy = Thy, Name = Name} 160in 161 case KernelSig.peek(const_table, k) of 162 NONE => raise ERR "mk_thy_const" ("No such constant: "^id2string k) 163 | SOME (id,basety) => if can (match_type basety) Ty then 164 Const(id, Ty) 165 else raise ERR "mk_thy_const" 166 ("Not a type instance: "^id2string k) 167end 168 169(* constructors - applications *) 170local val INCOMPAT_TYPES = Lib.C ERR "incompatible types" 171 fun lmk_comb err = 172 let fun loop (A,_) [] = A 173 | loop (A,typ) (tm::rst) = 174 let val (ty1,ty2) = with_exn Type.dom_rng typ err 175 in if type_of tm = ty1 176 then loop(App(A,tm),ty2) rst 177 else raise err 178 end 179 in fn (f,L) => loop(f, type_of f) L 180 end 181 val lmk_comb = (fn err => (* Profile.profile "lmk_comb" *)(lmk_comb err)) 182 val mk_comb0 = lmk_comb (INCOMPAT_TYPES "mk_comb") 183in 184 185fun mk_comb(r as (Abs(Var(_,Ty),_), Rand)) = 186 if type_of Rand = Ty then App r else raise INCOMPAT_TYPES "mk_comb" 187 | mk_comb(Rator,Rand) = mk_comb0 (Rator,[Rand]) 188 189val list_mk_comb = lmk_comb (INCOMPAT_TYPES "list_mk_comb") 190end; 191 192 193(* constructors - abstractions *) 194fun mk_abs(v, body) = 195 if is_var v then Abs(v, body) 196 else raise ERR "mk_abs" "Arg 1 not a variable" 197 198 199(* destructors *) 200 201fun dest_var (Var p) = p 202 | dest_var _ = raise ERR "dest_var" "Term not a variable" 203 204fun dest_const(Const(r, ty)) = (KernelSig.name_of r, ty) 205 | dest_const _ = raise ERR "dest_const" "Term not a constant" 206 207fun dest_thy_const t = let 208 open KernelSig 209in 210 case t of 211 Const(r, ty) => {Thy = seg_of r, Name = name_of r, Ty = ty} 212 | _ => raise ERR "dest_thy_const" "Term not a constant" 213end 214 215fun dest_comb(App p) = p 216 | dest_comb _ = raise ERR "dest_comb" "Term not a comb" 217 218val rator = #1 o dest_comb 219val rand = #2 o dest_comb 220 221fun dest_abs(Abs p) = p 222 | dest_abs _ = raise ERR "dest_abs" "Term not an abstraction" 223val bvar = #1 o dest_abs 224val body = #2 o dest_abs 225 226fun strip_binder binder = let 227 val f = case binder of 228 NONE => (fn t => if is_abs t then SOME t else NONE) 229 | SOME c => (fn t => let 230 val (rator, rand) = dest_comb t 231 in 232 if same_const rator c andalso is_abs rand then 233 SOME rand 234 else NONE 235 end handle HOL_ERR _ => NONE) 236 fun recurse acc t = 237 case f t of 238 NONE => (List.rev acc, t) 239 | SOME abs => let 240 val (v, body) = dest_abs abs 241 in 242 recurse (v::acc) body 243 end 244in 245 recurse [] 246end 247 248val strip_abs = strip_binder NONE 249 250(* free variable calculations *) 251 252fun var_compare p = 253 case p of 254 (Var(s1, ty1), Var(s2, ty2)) => let 255 in 256 case String.compare(s1, s2) of 257 EQUAL => Type.compare(ty1, ty2) 258 | x => x 259 end 260 | _ => raise ERR "var_compare" "variables required" 261 262val empty_varset = HOLset.empty var_compare 263 264local 265fun FV (v as Var _) A k = k (Lib.insert v A) 266 | FV (App(f, x)) A k = FV f A (fn q => FV x q k) 267 | FV (Abs(v, bdy)) A k = 268 if mem v A then FV bdy A k 269 else FV bdy A (fn q => k (Lib.set_diff q [v])) 270 | FV _ A k = k A 271in 272fun free_vars tm = FV tm [] Lib.I 273end 274 275fun free_vars_lr tm = let 276 fun FV (v as Var _) A = Lib.insert v A 277 | FV (App(f, x)) A = FV x (FV f A) 278 | FV (Abs(v, body)) A = if Lib.mem v A 279 then FV body A 280 else Lib.set_diff (FV body A) [v] 281 | FV _ A = A 282in 283 List.rev (FV tm []) 284end 285 286 287fun safe_delete(s, i) = HOLset.delete(s, i) handle HOLset.NotFound => s 288 289datatype FVaction = FVTM of term | DELvar of term 290 291fun FVL0 tlist acc = 292 case tlist of 293 [] => acc 294 | (FVTM t::ts) => let 295 in 296 case t of 297 (v as Var _) => FVL0 ts (HOLset.add(acc, v)) 298 | Const _ => FVL0 ts acc 299 | App(f, x) => FVL0 (FVTM f :: FVTM x :: ts) acc 300 | Abs(v, bdy) => 301 if HOLset.member(acc, v) then FVL0 (FVTM bdy :: ts) acc 302 else FVL0 (FVTM bdy :: DELvar v :: ts) acc 303 end 304 | DELvar v :: ts => FVL0 ts (safe_delete(acc, v)) 305 306fun FVL tlist = FVL0 (map FVTM tlist) 307 308 309local 310 fun vars (v as Var _) A = Lib.insert v A 311 | vars (App(f, x)) A = vars x (vars f A) 312 | vars (Abs(v, bdy)) A = vars bdy (vars v A) 313 | vars _ A = A 314in 315fun all_vars tm = vars tm [] 316end 317 318fun free_varsl tm_list = itlist (union o free_vars) tm_list [] 319fun all_varsl tm_list = itlist (union o all_vars) tm_list [] 320 321(* term comparison *) 322fun fast_term_eq t1 t2 = Portable.pointer_eq (t1,t2) 323structure Map = Binarymap 324val empty_env = Map.mkDict var_compare 325fun compare p = let 326 open Map 327 fun cmp n (E as (env1, env2)) (p as (t1,t2)) = 328 if n = 0 andalso fast_term_eq t1 t2 then EQUAL 329 else 330 case p of 331 (v1 as Var _, v2 as Var _) => let 332 in 333 case (peek(env1, v1), peek(env2, v2)) of 334 (NONE, NONE) => var_compare(v1, v2) 335 | (SOME _, NONE) => GREATER 336 | (NONE, SOME _) => LESS 337 | (SOME i, SOME j) => Int.compare(j, i) 338 (* flipping i & j deliberate; mimics deBruijn implementation's 339 behaviour, which would number variables in reverse order 340 from that done here *) 341 end 342 | (Var _, _) => LESS 343 | (_, Var _) => GREATER 344 | (Const(cid1, ty1), Const(cid2, ty2)) => let 345 in 346 case compare_cinfo(cid1, cid2) of 347 EQUAL => Type.compare(ty1, ty2) 348 | x => x 349 end 350 | (Const _, _) => LESS 351 | (_, Const _) => GREATER 352 | (App(M, N), App(P, Q)) => let 353 in 354 case cmp n E (M, P) of 355 EQUAL => cmp n E (N, Q) 356 | x => x 357 end 358 | (App _, Abs _) => LESS 359 | (Abs _, App _) => GREATER 360 | (Abs(v1, bdy1), Abs(v2, bdy2)) => let 361 in 362 case Type.compare(type_of v1, type_of v2) of 363 EQUAL => cmp (n + 1) (insert(env1, v1, n), insert(env2, v2, n)) 364 (bdy1, bdy2) 365 | x => x 366 end 367in 368 cmp 0 (empty_env, empty_env) p 369end 370 371val empty_tmset = HOLset.empty compare 372 373(* ---------------------------------------------------------------------- 374 All "atoms" (variables (bound or free) and constants). 375 376 Does not respect alpha-equivalence 377 ---------------------------------------------------------------------- *) 378 379fun all_atomsl tlist A = 380 case tlist of 381 [] => A 382 | t::ts => 383 let 384 in 385 case t of 386 Var _ => all_atomsl ts (HOLset.add(A,t)) 387 | Const _ => all_atomsl ts (HOLset.add(A,t)) 388 | App(Rator,Rand) => all_atomsl (Rator::Rand::ts) A 389 | Abs(v,body) => all_atomsl (body::ts) (HOLset.add(A,v)) 390 end 391 392fun all_atoms t = all_atomsl [t] empty_tmset 393 394 395fun aconv t1 t2 = compare(t1, t2) = EQUAL 396 397val term_eq = aconv 398 399fun free_in M N = let 400 val Mfvs = FVL [M] empty_varset 401 fun recurse t = 402 if compare(M, t) = EQUAL then true 403 else 404 case t of 405 Var _ => false 406 | Const _ => false 407 | App(f, x) => recurse f orelse recurse x 408 | Abs(v, bdy) => not (HOLset.member(Mfvs, v)) andalso 409 recurse bdy 410in 411 recurse N 412end 413 414fun var_occurs M = let 415 val v = case M of 416 Var v => v 417 | _ => raise ERR "var_occurs" "Term not a variable" 418 fun occ (Var u) = (v = u) 419 | occ (Const _) = false 420 | occ (App(f, x)) = occ f orelse occ x 421 | occ (Abs(Var u, body)) = u <> v andalso occ body 422 | occ (Abs _) = raise Fail "catastrophic invariant failure" 423in 424 occ 425end 426 427fun type_vars_in_term t = let 428 fun tyv t k = 429 case t of 430 Var(_, ty) => k (Type.type_vars ty) 431 | Const(_, ty) => k (Type.type_vars ty) 432 | App(f, x) => tyv f (fn fq => tyv x (fn xq => k (union fq xq))) 433 | Abs(x, b) => tyv x (fn xq => tyv b (fn bq => k (union xq bq))) 434in 435 tyv t Lib.I 436end 437 438(* two different substs; monomorphism restriction bites again; later code 439 gives these different types *) 440val emptyvsubst = Map.mkDict compare 441val emptysubst = Map.mkDict compare 442 443val empty_stringset = HOLset.empty String.compare 444 445(* it's hard to calculate free names simply by traversing a term because 446 of the situation where \x:ty1. body has x:ty1 and x:ty2 as free variables 447 in body. So, though it may be slightly less efficient, my solution here 448 is to just calculate the free variables and then calculate the image of 449 this set under name extraction *) 450val free_names = let 451 fun fold_name (v, acc) = HOLset.add(acc, #1 (dest_var v)) 452in 453 (fn t => HOLset.foldl fold_name empty_stringset (FVL [t] empty_varset)) 454end 455 456(* jrh's caml light HOL Light code 457let vsubst = 458 let mk_qcomb = qcomb(fun (x,y) -> Comb(x,y)) in 459 let rec vsubst theta tm = 460 match tm with 461 Var(_,_) -> (try snd(rev_assoc tm theta) 462 with Failure _ -> raise Unchanged) 463 | Const(_,_) -> raise Unchanged 464 | Comb(f,x) -> mk_qcomb (vsubst theta) (f,x) 465 | Abs(_,_) -> fst(vasubst theta tm) 466 and vasubst theta tm = 467 match tm with 468 Var(_,_) -> (try snd(rev_assoc tm theta),[tm] 469 with Failure _ -> raise Unchanged) 470 | Const(_,_) -> raise Unchanged 471 | Comb(l,r) -> (try let l',vs = vasubst theta l in 472 try let r',vt = vasubst theta r in 473 Comb(l',r'),union vs vt 474 with Unchanged -> Comb(l',r),vs 475 with Unchanged -> 476 let r',vt = vasubst theta r in Comb(l,r'),vt) 477 | Abs(v,bod) -> let theta' = filter (prefix<> v o snd) theta in 478 if theta' = [] then raise Unchanged else 479 let bod',vs = vasubst theta' bod in 480 let tms = map 481 (eval o fst o C rev_assoc theta') vs in 482 if exists (mem v) tms then 483 let fvs = itlist union tms (subtract (frees bod) vs) in 484 let v' = variant fvs v in 485 let bod',vars' = vasubst 486 (((eager [v'],v'),v)::theta') bod in 487 Abs(v',bod'),subtract vars' [v] 488 else 489 Abs(v,bod'),vs in 490 fun theta -> 491 if theta = [] then (fun tm -> tm) else 492 let atheta = map 493 (fun (t,x) -> if type_of t = snd(dest_var x) 494 then (lazy frees t,t),x 495 else failwith "vsubst: Bad substitution list") theta in 496 qtry(vsubst atheta);; 497*) 498 499fun set_name_variant nmset n = let 500 val next = Lexis.nameStrm n 501 fun loop n = if HOLset.member(nmset, n) then loop (next()) 502 else n 503in 504 loop n 505end 506 507 508local 509 open Map 510 511 datatype fvinfo = FVI of { current : term HOLset.set, 512 is_full : bool, 513 left : fvinfo option, (* also used for Abs *) 514 right : fvinfo option } 515 fun leaf (s, b) = 516 FVI {current = s, is_full = b, left = NONE, right = NONE} 517 fun current (FVI r) = #current r 518 fun is_full (FVI r) = #is_full r 519 fun left (FVI r) = valOf (#left r) 520 fun right (FVI r) = valOf (#right r) 521 (* computes a tree with information about the set of free variables in tm, 522 returns early when all redexes in theta have become bound *) 523 fun calculate_fvinfo theta_opt tm = 524 case tm of 525 Var _ => leaf (HOLset.singleton var_compare tm, true) 526 | Const _ => leaf (empty_varset, true) 527 | App (f, x) => 528 let 529 val fvs = calculate_fvinfo theta_opt f 530 val xvs = calculate_fvinfo theta_opt x 531 in 532 FVI {current = HOLset.union (current fvs, current xvs), 533 is_full = is_full fvs andalso is_full xvs, 534 left = SOME fvs, right = SOME xvs} 535 end 536 | Abs (v, body) => 537 let 538 val theta'_opt = Option.map 539 (fn theta => #1 (remove (theta, v)) handle NotFound => theta) 540 theta_opt 541 in 542 if isSome theta'_opt andalso numItems (valOf theta'_opt) = 0 then 543 (* return early *) 544 leaf (empty_varset, false) 545 else 546 let 547 val bodyvs = calculate_fvinfo theta'_opt body 548 in 549 FVI {current = safe_delete (current bodyvs, v), 550 is_full = is_full bodyvs, 551 left = SOME bodyvs, right = NONE} 552 end 553 end 554 (* expands a (possibly partial) tree with information about the set of free 555 variables in tm into a tree with full information *) 556 fun expand_partial_fvinfo tm fvi = 557 if is_full fvi then 558 raise Unchanged 559 else 560 case tm of 561 App (f, x) => 562 qcomb2 (fn (fvs, xvs) => 563 FVI {current = HOLset.union (current fvs, current xvs), 564 is_full = true, 565 left = SOME fvs, right = SOME xvs}) 566 (expand_partial_fvinfo f, expand_partial_fvinfo x) 567 (left fvi, right fvi) 568 | Abs (v, body) => 569 let 570 val bodyvs = expand_partial_fvinfo body (left fvi) 571 handle Option => calculate_fvinfo NONE body 572 in 573 FVI {current = safe_delete (current bodyvs, v), 574 is_full = true, 575 left = SOME bodyvs, right = NONE} 576 end 577 | _ => raise Fail "expand_partial_fvinfo: catastrophic invariant failure" 578 579 fun filtertheta theta fvset = let 580 (* Removes entries in theta for things not in fvset. theta likely to 581 be much smaller than fvset, so fold over that rather than the 582 other *) 583 fun foldthis (k,v,acc) = if HOLset.member(fvset, k) then insert(acc, k, v) 584 else acc 585 in 586 foldl foldthis emptyvsubst theta 587 end 588 589 fun augvsubst theta fvi tm = 590 case tm of 591 Var _ => (case peek (theta, tm) of NONE => raise Unchanged 592 | SOME (_, t) => t) 593 | Const _ => raise Unchanged 594 | App p => qcomb2 App 595 (augvsubst theta (left fvi), augvsubst theta (right fvi)) p 596 | Abs (v, body) => let 597 val theta' = #1 (remove (theta, v)) handle NotFound => theta 598 val _ = if numItems theta' = 0 then raise Unchanged else () 599 val (vname, vty) = dest_var v 600 val currentfvs = current fvi 601 val body_fvi = left fvi 602 (* first calculate the new names we are about to introduce into 603 the term *) 604 fun foldthis (k, v, acc) = 605 if HOLset.member (currentfvs, k) then 606 HOLset.union (acc, Susp.force (#1 v)) 607 else acc 608 val newnames = foldl foldthis empty_stringset theta' 609 in 610 if HOLset.member (newnames, vname) then 611 let 612 (* now need to vary v, avoiding both newnames, and also the 613 existing free-names of the whole term. *) 614 val body_fvi = expand_partial_fvinfo body body_fvi 615 handle Unchanged => body_fvi 616 val bodyfvs = current body_fvi 617 fun foldthis (fv, acc) = HOLset.add (acc, #1 (dest_var fv)) 618 val allfreenames = HOLset.foldl foldthis newnames bodyfvs 619 val new_vname = set_name_variant allfreenames vname 620 val new_v = mk_var (new_vname, vty) 621 val new_theta = 622 if HOLset.member (bodyfvs, v) then 623 let 624 val singleton = HOLset.singleton String.compare new_vname 625 in 626 insert (theta', v, 627 (Susp.delay (fn () => singleton), new_v)) 628 end 629 else theta' 630 in 631 Abs (new_v, augvsubst new_theta body_fvi body) 632 end 633 else 634 Abs (v, augvsubst theta' body_fvi body) 635 end 636 637 fun vsubst theta tm = 638 case tm of 639 Var _ => (case peek(theta, tm) of NONE => raise Unchanged 640 | SOME (_, t) => t) 641 | Const _ => raise Unchanged 642 | App p => qcomb App (vsubst theta) p 643 | Abs _ => let 644 val fvi = calculate_fvinfo (SOME theta) tm 645 val theta' = filtertheta theta (current fvi) 646 in 647 if numItems theta' = 0 then raise Unchanged 648 else augvsubst theta' fvi tm 649 end 650 651 fun ssubst theta t = 652 (* only used to substitute in fresh variables (genvars), so no 653 capture check -- potentially incorrect (because there is no 654 guarantee that genvars are actually fresh) *) 655 if numItems theta = 0 then raise Unchanged 656 else 657 case peek(theta, t) of 658 SOME v => v 659 | NONE => let 660 in 661 case t of 662 App p => qcomb App (ssubst theta) p 663 | Abs(v, body) => let 664 fun modify_theta (k,value,newtheta) = 665 if free_in v k then newtheta 666 else insert(newtheta, k, value) 667 val newtheta = foldl modify_theta emptysubst theta 668 in 669 Abs(v, ssubst newtheta body) 670 end 671 | _ => raise Unchanged 672 end 673 674 fun vsubst_insert (map, k, v) = 675 insert (map, k, (Susp.delay (fn () => free_names v), v)) 676in 677 678(* Due to the missing capture check in ssubst, subst can produce wrong results 679 (with accidental variable capture) unless all redexes in theta are 680 variables. 681 682 Therefore, all calls to subst that occur in Thm must ensure this 683 precondition. *) 684 685fun subst theta = 686 if null theta then I 687 else if List.all (is_var o #redex) theta then let 688 fun foldthis ({redex, residue}, acc) = let 689 val _ = type_of redex = type_of residue 690 orelse raise ERR "vsubst" "Bad substitution list" 691 in 692 if redex = residue then acc 693 else vsubst_insert (acc, redex, residue) 694 end 695 val atheta = List.foldl foldthis emptyvsubst theta 696 in 697 if numItems atheta = 0 then I 698 else (fn tm => vsubst atheta tm handle Unchanged => tm) 699 end 700 else let 701 fun foldthis ({redex,residue}, (theta1, theta2)) = let 702 val _ = type_of redex = type_of residue 703 orelse raise ERR "vsubst" "Bad substitution list" 704 val gv = genvar (type_of redex) 705 in 706 (insert (theta1, redex, gv), vsubst_insert (theta2, gv, residue)) 707 end 708 val (theta1, theta2) = 709 List.foldl foldthis (emptysubst, emptyvsubst) theta 710 in 711 (fn tm => vsubst theta2 (ssubst theta1 tm) 712 handle Unchanged => tm) 713 end 714 715end (* local *) 716 717 718(*---------------------------------------------------------------------------* 719 * Instantiate type variables in a term * 720 *---------------------------------------------------------------------------*) 721 722local 723 exception NeedToRename of term 724 structure Map = struct open Redblackmap end 725 fun inst1 theta ctxt t = 726 case t of 727 (c as Const(r, ty)) => (case ty_sub theta ty of 728 SAME => raise Unchanged 729 | DIFF ty => Const(r, ty)) 730 | (v as Var(name,ty0)) => let 731 val (changed, nv) = case ty_sub theta ty0 of 732 SAME => (false, v) 733 | DIFF ty => (true, Var(name, ty)) 734 in 735 case Map.peek (ctxt, nv) of 736 SOME oldtype => if oldtype = ty0 then () 737 else raise NeedToRename nv 738 | NONE => (); 739 if changed then nv 740 else raise Unchanged 741 end 742 | App p => qcomb App (inst1 theta ctxt) p 743 | Abs (v as Var(n, ty), body) => let 744 in 745 let 746 val (changed, v') = case ty_sub theta ty of 747 SAME => (false, v) 748 | DIFF ty' => (true, Var(n, ty')) 749 in let 750 val body' = SOME (inst1 theta (Map.insert(ctxt,v',ty)) body) 751 handle Unchanged => NONE 752 in 753 case (body', changed) of 754 (SOME t, _) => Abs(v', t) 755 | (NONE, true) => Abs(v', body) 756 | (NONE, false) => raise Unchanged 757 end handle e as NeedToRename v'' => 758 if v' = v'' then let 759 val free_names = free_names t 760 val new_name = set_name_variant free_names n 761 val newv = Var(new_name, ty) 762 in 763 inst1 theta ctxt (Abs(newv, subst [v |-> newv] body)) 764 end 765 else raise e 766 end 767 end 768 | Abs _ => raise Fail "inst1: catastrophic invariant failure!" 769in 770 771fun inst [] tm = tm 772 | inst theta tm = inst1 theta (Map.mkDict compare) tm handle Unchanged => tm 773end 774 775val inst : (hol_type, hol_type) Lib.subst -> term -> term = inst 776 777 778local 779 val FORMAT = ERR "list_mk_binder" 780 "expected first arg to be a constant of type :(<ty>_1 -> <ty>_2) -> <ty>_3" 781 fun check_opt NONE = Lib.I 782 | check_opt (SOME c) = 783 if not(is_const c) then raise FORMAT 784 else case total (fst o Type.dom_rng o fst o Type.dom_rng o type_of) c of 785 NONE => raise FORMAT 786 | SOME ty => (fn abs => 787 let val dom = fst(Type.dom_rng(type_of abs)) 788 in mk_comb (inst[ty |-> dom] c, abs) 789 end) 790in 791fun list_mk_binder binder = let 792 val f = check_opt binder 793 (* As of Mosml2.00, List.foldr is clearly not tail recursive, and you can 794 blow the stack with big lists here. Thus, the reversing of the list and 795 the use of foldl instead, relying on the fact that it's hard to imagine 796 not writing foldl tail-recursively *) 797in 798 fn (vlist, tm) => List.foldl (f o mk_abs) tm (List.rev vlist) 799end 800end (* local *) 801 802val list_mk_abs = list_mk_binder NONE 803 804 805fun beta_conv (App (Abs (v, body), x)) = 806 if x = v then body else subst [v |-> x] body 807 | beta_conv (App _) = 808 raise ERR "beta_conv" "LHS not an abstraction" 809 | beta_conv _ = 810 raise ERR "beta_conv" "Term not an application" 811 812val lazy_beta_conv = beta_conv 813 814fun eta_conv (Abs (x, App (f, x'))) = 815 if x = x' andalso not (free_in x f) then 816 f 817 else raise ERR "eta_conv" "Term not an eta-redex" 818 | eta_conv _ = 819 raise ERR "eta_conv" "Term not an eta-redex" 820 821 822(*---------------------------------------------------------------------------* 823 * Given a variable and a list of variables, if the variable does not exist * 824 * on the list, then return the variable. Otherwise, rename the variable and * 825 * try again. Note well that the variant uses only the name of the variable * 826 * as a basis for testing equality. Experience has shown that basing the * 827 * comparison on both the name and the type of the variable resulted in * 828 * needlessly confusing formulas occasionally being displayed in interactive * 829 * sessions. * 830 *---------------------------------------------------------------------------*) 831 832fun gen_variant P caller = 833 let fun var_name _ (Var(Name,_)) = Name 834 | var_name caller _ = raise ERR caller "not a variable" 835 fun vary vlist (Var(Name,Ty)) = 836 let val next = Lexis.nameStrm Name 837 val L = map (var_name caller) vlist 838 fun away s = if mem s L then away (next()) else s 839 fun loop name = 840 let val s = away name 841 in if P s then loop (next()) else s 842 end 843 in mk_var(loop Name, Ty) 844 end 845 | vary _ _ = raise ERR caller "2nd argument should be a variable" 846 in vary 847 end; 848 849val variant = gen_variant inST "variant" 850val prim_variant = gen_variant (K false) "prim_variant"; 851 852 853(* In the name-carrying implementation this operation is no longer constant 854 time *) 855fun rename_bvar newname t = 856 case t of 857 Abs(v, body) => let 858 val (nm, ty) = dest_var v 859 val newvar0 = mk_var(newname, ty) 860 val newvar = variant (free_vars t) newvar0 861 in 862 Abs(newvar, subst [v |-> newvar] body) 863 end 864 | _ => raise ERR "rename_bvar" "Term not an abstraction" 865 866 867 868(* ---------------------------------------------------------------------- 869 Matching 870 ---------------------------------------------------------------------- *) 871 872fun lookup x ids = let 873 fun look [] = if HOLset.member(ids, x) then SOME x else NONE 874 | look ({redex,residue}::t) = if x = redex then SOME residue else look t 875in 876 look 877end 878 879fun bvar_free (bvmap, tm) = let 880 (* return true if none of the free variables occur as keys in bvmap *) 881 fun recurse bs t = 882 case t of 883 v as Var _ => HOLset.member(bs, v) orelse 884 not (isSome (Map.peek(bvmap, v))) 885 | Const _ => true 886 | App(f,x) => recurse bs f andalso recurse bs x 887 | Abs(v, body) => recurse (HOLset.add(bs, v)) body 888in 889 Map.numItems bvmap = 0 orelse recurse empty_varset tm 890end 891 892fun MERR s = raise ERR "raw_match_term" s 893 894fun add_id v {ids, patbvars, obbvars, theta, n} = 895 {ids = HOLset.add(ids, v), patbvars = patbvars, obbvars = obbvars, n = n, 896 theta = theta} 897fun add_binding v tm {ids, patbvars, obbvars, theta, n} = 898 {ids = ids, patbvars = patbvars, obbvars = obbvars, n = n, 899 theta = (v |-> tm) :: theta} 900 901type tminfo = {ids : term HOLset.set, n : int, 902 patbvars : (term,int)Map.dict, 903 obbvars : (term,int)Map.dict, 904 theta : (term,term) Lib.subst} 905 906datatype tmpair = TMP of term * term 907 | BVrestore of {patbvars : (term,int)Map.dict, 908 obbvars : (term,int)Map.dict, 909 n : int} 910 911fun RM patobs (theta0 as (tminfo, tyS)) = 912 case patobs of 913 [] => theta0 914 | TMP po::rest => let 915 in 916 case po of 917 (v as Var(_, ty), tm) => let 918 in 919 case Map.peek(#patbvars tminfo, v) of 920 NONE => (* var on left not bound *) let 921 in 922 if bvar_free (#obbvars tminfo, tm) then 923 RM rest ((case lookup v (#ids tminfo) (#theta tminfo) of 924 NONE => if v = tm then add_id v tminfo 925 else add_binding v tm tminfo 926 | SOME tm' => if aconv tm' tm then tminfo 927 else MERR "double bind"), 928 Type.raw_match_type ty (type_of tm) tyS) 929 else 930 MERR "Attempt to capture bound variable" 931 end 932 | SOME i => if is_var tm andalso 933 Map.peek(#obbvars tminfo, tm) = SOME i 934 then 935 RM rest theta0 936 else MERR "Bound var doesn't match" 937 end 938 | (Const(c1, ty1), Const(c2, ty2)) => 939 if c1 <> c2 then MERR ("Different constants: "^c2string c1^" and "^ 940 c2string c2) 941 else RM rest (tminfo, Type.raw_match_type ty1 ty2 tyS) 942 | (App(f1, x1), App(f2, x2)) => 943 RM (TMP (f1, f2) :: TMP (x1, x2) :: rest) theta0 944 | (Abs(x1, bdy1), Abs(x2, bdy2)) => let 945 val tyS' = Type.raw_match_type (type_of x1) (type_of x2) tyS 946 val {ids, patbvars, obbvars, n, theta} = tminfo 947 in 948 RM (TMP (bdy1, bdy2) :: 949 BVrestore {patbvars = patbvars, obbvars = obbvars, n = n} :: 950 rest) 951 ({ids = #ids tminfo, n = n + 1, theta = theta, 952 patbvars = Map.insert(patbvars, x1, n), 953 obbvars = Map.insert(obbvars, x2, n)}, tyS') 954 end 955 | _ => MERR "different constructors" 956 end 957 | BVrestore{patbvars, obbvars, n} :: rest => let 958 val {ids, theta, ...} = tminfo 959 in 960 RM rest ({ids = ids, theta = theta, patbvars = patbvars, 961 obbvars = obbvars, n = n}, tyS) 962 end 963 964(* tyfixed: list of type variables that mustn't be instantiated 965 tmfixed: set of term variables that mustn't be instantiated 966 pat : term "pattern" to match 967 theta0 : an existing matching 968*) 969 970fun postRM (tmtheta : tminfo, tyS) = ((#theta tmtheta, #ids tmtheta), tyS) 971 972val empty_intsubst = Map.mkDict compare 973 974fun raw_match tyfixed tmfixed pat ob (tmS, tyS) = 975 postRM (RM [TMP (pat, ob)] ({ids = tmfixed, n = 0, theta = tmS, 976 patbvars = empty_intsubst, 977 obbvars = empty_intsubst}, 978 (tyS, tyfixed))) 979 980(* val raw_match0 = raw_match 981fun raw_match tyf tmf pat ob = 982 Profile.profile "raw_match" (raw_match0 tyf tmf pat ob) *) 983 984fun norm_subst ((tmS,_),(tyS,_)) = 985 let val Theta = inst tyS 986 fun del A [] = A 987 | del A ({redex,residue}::rst) = 988 del (let val redex' = Theta(redex) 989 in if residue=redex' then A else (redex' |-> residue)::A 990 end) rst 991 in (del [] tmS,tyS) 992 end 993 994fun match_terml tyfixed tmfixed pat ob = 995 norm_subst (raw_match tyfixed tmfixed pat ob ([],[])) 996 997val match_term = match_terml [] empty_varset; 998 999fun size acc tlist = 1000 case tlist of 1001 [] => acc 1002 | t :: ts => let 1003 in 1004 case t of 1005 Var _ => size (1 + acc) ts 1006 | Const _ => size (1 + acc) ts 1007 | App(t1, t2) => size (1 + acc) (t1 :: t2 :: ts) 1008 | Abs(_, b) => size (1 + acc) (b :: ts) 1009 end 1010 1011fun term_size t = size 0 [t] 1012 1013 1014 1015 1016val imp = let 1017 val k = {Name = "==>", Thy = "min"} 1018in 1019 prim_new_const k (bool --> bool --> bool) 1020end 1021 1022val equality = let 1023 val k = {Name = "=", Thy = "min"} 1024in 1025 prim_new_const k (alpha --> alpha --> bool) 1026end 1027 1028val select = let 1029 val k = {Name = "@", Thy = "min"} 1030in 1031 prim_new_const k ((alpha --> bool) --> alpha) 1032end 1033 1034fun dest_eq_ty t = let 1035 val (fx, y) = dest_comb t 1036 val (f, x) = dest_comb fx 1037in 1038 if same_const f equality then (x, y, type_of x) 1039 else raise ERR "dest_eq_ty" "Term not an equality" 1040end 1041 1042fun prim_mk_eq ty t1 t2 = 1043 App(App(inst [alpha |-> ty] equality, t1), t2) 1044 1045(*val prim_mk_eq = 1046 (fn ty => fn t1 => Profile.profile "prim_mk_eq" (prim_mk_eq ty t1)) *) 1047 1048fun prim_mk_imp t1 t2 = App(App(imp, t1), t2) 1049 1050(* val prim_mk_imp = (fn t1 => Profile.profile "prim_mk_imp" (prim_mk_imp t1))*) 1051 1052(* ---------------------------------------------------------------------- 1053 dest_term and the lambda type 1054 ---------------------------------------------------------------------- *) 1055 1056datatype lambda = 1057 VAR of string * hol_type 1058 | CONST of {Name: string, Thy: string, Ty: hol_type} 1059 | COMB of term * term 1060 | LAMB of term * term 1061 1062fun dest_term M = 1063 case M of 1064 Const _ => CONST (dest_thy_const M) 1065 | Var p => VAR p 1066 | App p => COMB p 1067 | Abs p => LAMB p 1068 1069fun identical t1 t2 = t1 = t2 1070 1071(*---------------------------------------------------------------------------* 1072 * Raw syntax prettyprinter for terms. * 1073 *---------------------------------------------------------------------------*) 1074 1075val app = "@" 1076val lam = "|" 1077val percent = "%" 1078 1079datatype pptask = ppTM of term | ppLAM | ppAPP of int 1080fun pp_raw_term index tm = let 1081 fun mkAPP (ppAPP n :: rest) = ppAPP (n + 1) :: rest 1082 | mkAPP rest = ppAPP 1 :: rest 1083 fun pp acc tasklist = 1084 case tasklist of 1085 [] => String.concat (List.rev acc) 1086 | ppTM (Abs(Bvar, Body)) :: rest => 1087 pp acc (ppTM Bvar :: ppTM Body :: ppLAM :: rest) 1088 | ppTM (App(Rator, Rand)) :: rest => 1089 pp acc (ppTM Rator :: ppTM Rand :: mkAPP rest) 1090 | ppTM vc :: rest => 1091 pp (percent ^ Int.toString (index vc) :: acc) rest 1092 | ppLAM :: rest => pp ("|" :: acc) rest 1093 | ppAPP n :: rest => 1094 pp ("@" ^ (if n = 1 then "" else Int.toString n) :: acc) rest 1095in 1096 pp [] [ppTM tm] 1097end 1098val write_raw = pp_raw_term 1099 1100local 1101datatype tok = lam | id of int | app of int 1102open StringCvt 1103 1104fun readtok (c : (char, cs) reader) cs = let 1105 val intread = Int.scan DEC c 1106in 1107 case c cs of 1108 NONE => NONE 1109 | SOME (#"|",cs') => SOME (lam,cs') 1110 | SOME (#"@",cs') => 1111 (case intread cs' of 1112 NONE => SOME (app 1,cs') 1113 | SOME (i,cs'') => SOME (app i, cs'')) 1114 | SOME (c,cs') => (case intread cs' of 1115 NONE => NONE 1116 | SOME (i,cs'') => SOME(id i, cs'')) 1117end 1118 1119fun parse tmv c cs0 = let 1120 fun adv cs = case readtok c cs of NONE => (NONE, cs) 1121 | SOME (t, cs') => (SOME t, cs') 1122 fun parse_term stk cur = 1123 case (stk, cur) of 1124 ([t], (NONE,cs)) => SOME (t, cs) 1125 | ([], (NONE, _)) => raise Fail "raw_parse.eof: empty stack" 1126 | (_, (NONE, _)) => raise Fail "raw_parse.eof: large stack" 1127 | (body :: bvar :: stk, (SOME lam, cs')) => 1128 parse_term (Abs(bvar,body) :: stk) (adv cs') 1129 | (_, (SOME lam, _)) => raise Fail "raw_parse.abs: short stack" 1130 | (stk, (SOME (app i), cs')) => doapp i stk cs' 1131 | (stk, (SOME (id i), cs')) => 1132 parse_term (Vector.sub(tmv, i) :: stk) (adv cs') 1133 and doapp i stk cs = 1134 if i = 0 then parse_term stk (adv cs) 1135 else 1136 case stk of 1137 x :: f :: stk => doapp (i - 1) (App(f,x) :: stk) cs 1138 | _ => raise Fail "raw_parse.app: short stack" 1139in 1140 parse_term [] (adv cs0) 1141end 1142 1143 1144in 1145 1146fun read_raw tmv s = 1147 valOf (scanString (parse tmv) s) 1148 1149end (* local *) 1150 1151end (* struct *) 1152