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