1structure HolKernel =
2struct
3
4  open Feedback Globals Lib Type Term Thm Theory
5  open Definition
6
7
8(*---------------------------------------------------------------------------
9     Miscellaneous other stuff that builds on top of kernel facilities.
10 ---------------------------------------------------------------------------*)
11
12infixr -->;  infix |->;
13
14local
15  val ERR = mk_HOL_ERR "HolKernel"
16in
17
18(*---------------------------------------------------------------------------
19          General term operations
20 ---------------------------------------------------------------------------*)
21
22fun dest_monop c e M =
23   let
24      val (c1, N) = with_exn dest_comb M e
25   in
26      if same_const c c1 then N else raise e
27   end
28
29local
30   fun dest tm =
31      let
32         val (Rator, N) = dest_comb tm
33         val (c, M) = dest_comb Rator
34      in
35         (c, (M, N))
36      end
37in
38   fun dest_binop c e tm =
39      let
40         val (c1, pair) = with_exn dest tm e
41      in
42         if same_const c c1 then pair else raise e
43      end
44end
45
46fun dest_triop p e M =
47   let
48      val (f, z) = with_exn dest_comb M e
49      val (x, y) = dest_binop p e f
50   in
51      (x, y, z)
52   end
53
54(*---------------------------------------------------------------------------*)
55(* Take a binder apart. Fails on paired binders.                             *)
56(*---------------------------------------------------------------------------*)
57
58local
59   fun dest M = let val (c, Rand) = dest_comb M in (c, dest_abs Rand) end
60in
61   fun dest_binder c e M =
62      let
63         val (c1, p) = with_exn dest M e
64      in
65         if same_const c c1 then p else raise e
66      end
67end
68
69local
70   fun dest M =
71      let val (Rator, Rand) = dest_comb M in (dest_thy_const Rator, Rand) end
72in
73   fun sdest_monop (name, thy) e M =
74      let
75         val ({Name, Thy, ...}, Rand) = with_exn dest M e
76      in
77         if Name = name andalso Thy = thy then Rand else raise e
78      end
79end
80
81local
82   fun dest tm =
83      let
84         val (Rator, N) = dest_comb tm
85         val (c, M) = dest_comb Rator
86      in
87         (dest_thy_const c, (M, N))
88      end
89in
90   fun sdest_binop (name, thy) e tm =
91      let
92         val ({Name, Thy, ...}, pair) = with_exn dest tm e
93      in
94         if Name = name andalso Thy = thy then pair else raise e
95      end
96end
97
98local
99   fun dest M =
100       let val (c, Rand) = dest_comb M
101       in (dest_thy_const c, dest_abs Rand)
102       end
103in
104   fun sdest_binder (name, thy) e M =
105      let
106         val ({Name, Thy, ...}, p) = with_exn dest M e
107      in
108         if Name = name andalso Thy = thy then p else raise e
109      end
110end
111
112(* Breaks term down until binop no longer occurs at top level in result list *)
113
114fun strip_binop_opt dest =
115   let
116      fun strip A [] = rev A
117        | strip A (h :: t) =
118            case dest h of
119               NONE => strip (h :: A) t
120             | SOME (c1, c2) => strip A (c1 :: c2 :: t)
121   in
122      strip [] o Lib.list_of_singleton
123   end
124
125fun strip_binop dest = strip_binop_opt (total dest);
126
127(* For right-associative binary operators,
128  or such as dest_abs, SPEC_VAR, dom_rng, dest_imp. Tail recursive. *)
129
130local
131fun spine_binop' dest =
132   let
133      fun strip A tm =
134         case dest tm of
135            NONE => (tm, A)
136          | SOME (l, r) => strip (l :: A) r
137   in
138      strip []
139   end
140in
141fun spine_binop dest tm = rev ((op ::) (spine_binop' dest tm)) ;
142
143fun strip_gen_left_opt dest t =
144  let val (tm, A) = spine_binop' dest t in (rev A, tm) end ;
145end (* local fun spine_binop' *)
146
147fun strip_gen_left dest = strip_gen_left_opt (total dest) ;
148
149(* For left-associative binary operators.  Tail recursive *)
150
151fun strip_gen_right_opt dest =
152   let
153     fun strip A tm =
154         case dest tm of
155           NONE => (tm, A)
156         | SOME (l, r) => strip (r :: A) l
157   in
158      strip []
159   end
160
161fun lspine_binop dest tm = (op ::) (strip_gen_right_opt dest tm) ;
162
163fun strip_gen_right dest = strip_gen_right_opt (total dest) ;
164
165(* For right-associative binary operators. Tail recursive. *)
166
167fun list_mk_rbinop mk_binop alist =
168   case List.rev alist of
169      [] => raise ERR "list_mk_rbinop" "empty list"
170    | h :: t => rev_itlist mk_binop t h
171
172(* For left-associative binary operators. Tail recursive. *)
173
174fun list_mk_lbinop _ [] = raise ERR "list_mk_lbinop" "empty list"
175  | list_mk_lbinop mk_binop (h :: t) = rev_itlist (C mk_binop) t h
176
177fun mk_binder c f (p as (Bvar, _)) =
178   mk_comb (inst [alpha |-> type_of Bvar] c, mk_abs p)
179   handle HOL_ERR {message, ...} => raise ERR f message
180
181fun list_mk_fun (dtys, rty) = List.foldr op--> rty dtys
182
183val strip_fun =
184   let
185      val dest = total dom_rng
186      fun strip acc ty =
187         case dest ty of
188            SOME (d, r) => strip (d :: acc) r
189          | NONE => (rev acc, ty)
190   in
191      strip []
192   end
193
194val strip_comb =
195   let
196      val destc = total dest_comb
197      fun strip rands M =
198         case destc M of
199            NONE => (M, rands)
200          | SOME (Rator, Rand) => strip (Rand :: rands) Rator
201   in
202      strip []
203   end
204
205fun dest_quadop c e tm =
206   case with_exn strip_comb tm e of
207      (t, [t1, t2, t3, t4]) =>
208         if same_const t c then (t1, t2, t3, t4) else raise e
209    | _ => raise e
210
211local
212   val mk_aty = list_mk_rbinop (Lib.curry Type.-->)
213   val args = fst o strip_fun o Term.type_of
214in
215   fun list_mk_icomb tm xs =
216      let
217         val tyl = mk_aty (Lib.with_exn List.take (args tm, List.length xs)
218                                        (ERR "" "too many arguments"))
219         val tyr = mk_aty (List.map Term.type_of xs)
220      in
221         Term.list_mk_comb (Term.inst (Type.match_type tyl tyr) tm, xs)
222      end
223      handle HOL_ERR {message, ...} => raise ERR "list_mk_icomb" message
224
225   fun syntax_fns
226      {n: int, make: term -> 'a -> term, dest: term -> exn -> term -> 'b}
227      thy name =
228      let
229         val ERR = Feedback.mk_HOL_ERR (thy ^ "Syntax")
230         val tm = Term.prim_mk_const {Name = name, Thy = thy}
231         val () =
232            ignore (List.length (args tm) = n
233                    orelse raise ERR "syntax_fns" "bad number of arguments")
234         val d = dest tm (ERR ("dest_" ^ name) "")
235      in
236         (tm,
237          fn v => Lib.with_exn (make tm) v (ERR ("mk_" ^ name) ""): term,
238          d: term -> 'b,
239          can d)
240      end
241end
242
243fun mk_monop tm = list_mk_icomb tm o Lib.list_of_singleton
244fun mk_binop tm = list_mk_icomb tm o Lib.list_of_pair
245fun mk_triop tm = list_mk_icomb tm o Lib.list_of_triple
246fun mk_quadop tm = list_mk_icomb tm o Lib.list_of_quadruple
247
248val syntax_fns1 = syntax_fns {n = 1, make = mk_monop, dest = dest_monop}
249val syntax_fns2 = syntax_fns {n = 2, make = mk_binop, dest = dest_binop}
250val syntax_fns3 = syntax_fns {n = 3, make = mk_triop, dest = dest_triop}
251val syntax_fns4 = syntax_fns {n = 4, make = mk_quadop, dest = dest_quadop}
252
253(*---------------------------------------------------------------------------*
254 * Used to implement natural deduction style discharging of hypotheses. All  *
255 * hypotheses alpha-convertible to the dischargee are removed.               *
256 *---------------------------------------------------------------------------*)
257
258fun disch (w, wl) = List.filter (not o Term.aconv w) wl
259
260(*---------------------------------------------------------------------------*
261 * Search a term for a sub-term satisfying the predicate P. If application   *
262 * of P raises an exception, that propagates to the caller. Therefore,       *
263 * P should be a total predicate: otherwise, the caller won't know whether   *
264 * the search failed because the sought-for subterm is not there, or because *
265 * P failed.                                                                 *
266 *---------------------------------------------------------------------------*)
267
268fun find_term P =
269   let
270      fun find_tm tm =
271         if P tm
272            then tm
273         else if is_abs tm
274            then find_tm (body tm)
275         else case Lib.total dest_comb tm of
276                 SOME (Rator, Rand) =>
277                    (find_tm Rator handle HOL_ERR _ => find_tm Rand)
278               | NONE => raise ERR "find_term" ""
279   in
280      find_tm
281   end
282
283
284local
285   datatype action = SEARCH of term | POP
286in
287   fun gen_find_term f t =
288      let
289        fun search bvs actions =
290           case actions of
291              [] => NONE
292            | POP :: alist => search (tl bvs) alist
293            | SEARCH t :: alist => (case f (bvs, t) of
294                                        NONE => subterm bvs alist t
295                                      | x => x)
296        and subterm bvs alist t =
297           case dest_term t of
298              COMB (t1, t2) => search bvs (SEARCH t1 :: SEARCH t2 :: alist)
299            | LAMB (bv, t) => search (bv :: bvs) (SEARCH t :: POP :: alist)
300            | _ => search bvs alist
301   in
302      search [] [SEARCH t]
303   end
304   fun gen_find_terms f t =
305       let
306         fun search bvs actions acc =
307             case actions of
308                 [] => acc
309               | POP :: alist => search (tl bvs) alist acc
310               | SEARCH t :: alist =>
311                 (case f (bvs, t) of
312                      NONE => subterm bvs alist acc t
313                    | SOME x => subterm bvs alist (x::acc) t)
314         and subterm bvs alist acc t =
315             case dest_term t of
316                 COMB(t1, t2) => search bvs (SEARCH t1 :: SEARCH t2 :: alist)
317                                        acc
318               | LAMB (bv, t) => search (bv::bvs) (SEARCH t :: POP :: alist) acc
319               | _ => search bvs alist acc
320       in
321         search [] [SEARCH t] []
322       end
323end (* local *)
324
325(* ----------------------------------------------------------------------
326    bvk_find_term :
327     (term list * term -> bool) -> (term -> 'a) -> term -> 'a option
328
329    [bvk_find_term P k tm] searches tm for a sub-term satisfying P and
330    calls the continuation k on the first that it finds.  If k
331    succeeds on this sub-term, the result is wrapped in SOME.  If k
332    raises a HOL_ERR exception, control returns to bvk_find_term,
333    which continues to look for a sub-term satisfying P.  Other
334    exceptions are returned to the caller. If there is no sub-term
335    that both satisfies P and which k operates on successfully, the
336    result is NONE.
337
338    The search order is top-down, left-to-right (i.e., rators of combs
339    are examined before rands).
340
341    As with find_term, P should be total.  In addition, P is given not
342    just the sub-term of interest, but also the stack of bound
343    variables that have scope over the sub-term, with the innermost
344    bound variables appearing earlier in the list.
345   ---------------------------------------------------------------------- *)
346
347fun bvk_find_term P k =
348    gen_find_term (fn x => if P x then SOME (k (#2 x)) handle HOL_ERR _ => NONE
349                           else NONE)
350
351(*---------------------------------------------------------------------------
352 * find_terms: (term -> bool) -> term -> term list
353 *
354 *  Find all subterms in a term that satisfy a given predicate p.
355 *
356 * Added TFM 88.03.31
357 *---------------------------------------------------------------------------*)
358
359fun find_terms P =
360   let
361      open Uref
362      val tms = Uref.new []
363      fun find_tms tm =
364         (if P tm then tms := tm :: (!tms) else ()
365          ; find_tms (body tm)
366            handle HOL_ERR _ =>
367               case Lib.total dest_comb tm of
368                  SOME (r1, r2) => (find_tms r1; find_tms r2)
369                | NONE => ())
370   in
371      fn tm =>
372         let
373            val r = (find_tms tm; (!tms))
374         in
375            tms := []; r
376         end
377   end
378
379(* ----------------------------------------------------------------------
380    find_maximal_terms[l]
381
382    finds sub-terms within a term, but doesn't look into sub-terms that
383    match the provided predicate.  The find_maximal_termsl version
384    returns the terms as a list rather than a set.
385   ---------------------------------------------------------------------- *)
386
387fun find_maximal_terms P t =
388   let
389      fun recurse acc tlist =
390         case tlist of
391            [] => acc
392          | t :: ts =>
393               if P t
394                  then recurse (HOLset.add (acc, t)) ts
395               else case dest_term t of
396                       COMB (f, x) => recurse acc (f :: x :: ts)
397                     | LAMB (v, b) => recurse acc (b :: ts)
398                     | _ => recurse acc ts
399   in
400      recurse empty_tmset [t]
401   end
402
403fun find_maximal_termsl P t = HOLset.listItems (find_maximal_terms P t)
404
405(* ----------------------------------------------------------------------
406    term_size
407
408    Returns a term's size.  There's no logical significance to this
409    number, but it can be useful.
410   ---------------------------------------------------------------------- *)
411
412fun term_size t =
413   let
414      fun recurse acc tlist =
415         case tlist of
416            [] => acc
417          | t :: ts =>
418              (case dest_term t of
419                  COMB (f, x) => recurse acc (f :: x :: ts)
420                | LAMB (v, b) => recurse (1 + acc) (b :: ts)
421                | _ => recurse (1 + acc) ts)
422   in
423      recurse 0 [t]
424   end
425
426(*---------------------------------------------------------------------------
427 * Subst_occs
428 * Put a new variable in tm2 at designated (and free) occurrences of redex.
429 * Rebuilds the entire term.
430 *---------------------------------------------------------------------------*)
431
432local
433fun splice ({redex, ...}:{redex:term, residue:term}) v occs tm2 =
434   let fun graft (r as {occs=[], ...}) = r
435         | graft {tm, occs, count} =
436          if term_eq redex tm
437          then if (List.hd occs = count + 1)
438               then {tm=v, occs=List.tl occs, count=count+1}
439               else {tm=tm, occs=occs, count=count+1}
440          else if (is_comb tm)
441               then let val (Rator, Rand) = dest_comb tm
442                        val {tm=Rator', occs=occs', count=count'} =
443                                        graft {tm=Rator, occs=occs, count=count}
444                        val {tm=Rand', occs=occs'', count=count''} =
445                                        graft {tm=Rand, occs=occs', count=count'}
446                    in {tm=mk_comb (Rator', Rand'),
447                        occs=occs'', count=count''}
448                    end
449               else if is_abs tm
450                    then let val (Bvar, Body) = dest_abs tm
451                             val {tm, count, occs} =
452                                        graft{tm=Body, count=count, occs=occs}
453                         in {tm=mk_abs (Bvar, tm),
454                             count=count, occs=occs}
455                         end
456                    else {tm=tm, occs=occs, count=count}
457   in #tm (graft {tm=tm2, occs=occs, count=0})
458   end
459
460fun rev_itlist3 f L1 L2 L3 base_value =
461 let fun rev_it3 (a::rst1) (b::rst2) (c::rst3) base =
462             rev_it3 rst1 rst2 rst3 (f a b c base)
463       | rev_it3 [] [] [] base = base
464       | rev_it3 _ _ _ _ = raise ERR "rev_itlist3"
465                                  "not all lists have same size"
466 in rev_it3 L1 L2 L3 base_value
467 end
468
469val sort = Lib.sort (Lib.curry (op <=) : int -> int -> bool)
470in
471fun subst_occs occ_lists tm_subst tm =
472   let val occ_lists' = map sort occ_lists
473       val (new_vars, theta) =
474               Lib.itlist (fn {redex, residue} => fn (V, T) =>
475                         let val v = genvar (type_of redex)
476                         in (v::V,  (v |-> residue)::T)  end)
477                      tm_subst ([],[])
478       val template = rev_itlist3 splice tm_subst new_vars occ_lists' tm
479   in subst theta template
480   end
481end
482
483(*---------------------------------------------------------------------------
484       Higher order matching (from jrh via Michael Norrish - June 2001)
485 ---------------------------------------------------------------------------*)
486
487local
488  exception NOT_FOUND
489  fun find_residue red [] = raise NOT_FOUND
490    | find_residue red ({redex, residue}::rest) =
491        if aconv red redex then residue else find_residue red rest
492  fun find_residue_eq red [] = raise NOT_FOUND
493    | find_residue_eq red ({redex, residue}::rest) =
494        if red = redex then residue else find_residue_eq red rest
495  fun in_dom x [] = false
496    | in_dom x ({redex, residue}::rest) = aconv x redex orelse in_dom x rest
497  fun in_domeq x [] = false
498    | in_domeq x ({redex,residue}::rest) = x = redex orelse in_domeq x rest
499
500  (* for terms *)
501  fun safe_insert (n as {redex, residue}) l =
502    let
503      val z = find_residue redex l
504    in
505      if aconv residue z then l
506      else failwith "match: safe_insert"
507    end handle NOT_FOUND => n::l
508
509  fun safe_inserteq (n as {redex,residue}) l =
510    let
511      val z = find_residue redex l
512    in
513      if residue = z then l
514      else failwith "match: safe_insert"
515    end handle NOT_FOUND => n::l
516  val mk_dummy = let
517    val name = fst (dest_var (genvar Type.alpha))
518  in fn ty => mk_var (name, ty)
519  end
520
521
522  fun term_pmatch lconsts env vtm ctm (sofar as (insts, homs)) =
523    if is_var vtm then let
524        val ctm' = find_residue vtm env
525      in
526        if aconv ctm' ctm then sofar else failwith "term_pmatch"
527      end handle NOT_FOUND =>
528                 if HOLset.member (lconsts, vtm) then
529                   if aconv ctm vtm then sofar
530                   else
531                     failwith "term_pmatch: can't instantiate local constant"
532                 else (safe_insert (vtm |-> ctm) insts, homs)
533    else if is_const vtm then let
534        val {Thy = vthy, Name = vname, Ty = vty} = dest_thy_const vtm
535        val {Thy = cthy, Name = cname, Ty = cty} = dest_thy_const ctm
536      in
537        if vname = cname andalso vthy = cthy then
538          if cty = vty then sofar
539          else (safe_insert (mk_dummy vty |-> mk_dummy cty) insts, homs)
540        else failwith "term_pmatch"
541      end
542    else if is_abs vtm then let
543        val (vv, vbod) = dest_abs vtm
544        val (cv, cbod) = dest_abs ctm
545        val (_, vty) = dest_var vv
546        val (_, cty) = dest_var cv
547        val sofar' = (safe_insert (mk_dummy vty |-> mk_dummy cty) insts, homs)
548      in
549        term_pmatch lconsts ((vv |-> cv)::env) vbod cbod sofar'
550      end
551    else let
552        val vhop = repeat rator vtm
553      in
554        if is_var vhop andalso not (HOLset.member (lconsts, vhop)) andalso
555           not (in_dom vhop env)
556        then let
557            val vty = type_of vtm
558            val cty = type_of ctm
559            val insts' = if vty = cty then insts
560                         else safe_insert (mk_dummy vty |-> mk_dummy cty) insts
561          in
562            (insts', (env, ctm, vtm)::homs)
563          end
564        else let
565            val (lv, rv) = dest_comb vtm
566            val (lc, rc) = dest_comb ctm
567            val sofar' = term_pmatch lconsts env lv lc sofar
568          in
569            term_pmatch lconsts env rv rc sofar'
570          end
571      end
572
573(*
574fun get_type_insts avoids L =
575 let val avtys = itlist (fn ty => fn (p,o) => (ty-->p, ty-->o))
576                        avoids (bool,bool)
577     val (pat,ob) = itlist (fn {redex,residue} => fn (pat,ob) =>
578                               (type_of redex-->pat, type_of residue-->ob))
579                         L avtys
580
581 in match_type pat ob
582 end
583
584fun get_type_insts avoids L =
585 let val tytheta = itlist (fn {redex,residue} =>
586          match_type_in_context (snd (dest_var redex)) (type_of residue))
587                     L []
588 in if null (intersect avoids (map #residue tytheta))
589    then tytheta
590    else raise ERR "get_type_insts" "attempt to bind fixed type variable"
591 end
592*)
593fun get_type_insts avoids L (tyS, Id) =
594 itlist (fn {redex, residue} => fn Theta =>
595          raw_match_type (snd (dest_var redex)) (type_of residue) Theta)
596       L (tyS, union avoids Id)
597
598fun separate_insts tyavoids insts = let
599  val (realinsts, patterns) = partition (is_var o #redex) insts
600  val betacounts =
601      if null patterns then []
602      else
603        itlist (fn {redex = p, ...} =>
604                   fn sof => let
605                        val (hop, args) = strip_comb p
606                      in
607                        safe_inserteq (hop |-> length args) sof
608                      end handle HOL_ERR _ =>
609                                 (HOL_WARNING "" ""
610                                  "Inconsistent patterning in h.o. match";
611                                  sof))
612        patterns []
613  val tyins = get_type_insts tyavoids realinsts ([],[])
614in
615  (betacounts,
616   mapfilter (fn {redex = x, residue = t} => let
617                   val x' = let val (xn, xty) = dest_var x
618                            in
619                              mk_var (xn, type_subst (#1 tyins) xty)
620                            end
621                 in
622                   if aconv t x' then failwith "" else {redex = x', residue = t}
623                 end) realinsts,
624   tyins)
625end
626
627val tmmem = op_mem aconv
628fun tyenv_in_dom x (env, idlist) = mem x idlist orelse in_domeq x env
629fun tyenv_find_residue x (env, idlist) = if mem x idlist then x
630                                         else find_residue_eq x env
631fun tyenv_safe_insert (t as {redex, residue}) (E as (env, idlist)) = let
632  val existing = tyenv_find_residue redex E
633in
634  if existing = residue then E else failwith "Type bindings clash"
635end handle NOT_FOUND => if redex = residue then (env, redex::idlist)
636                        else (t::env, idlist)
637
638fun beta_normalise0 t = let
639  val bn0 = beta_normalise0
640  fun bn1 t = case bn0 t of NONE => SOME t | x => x
641in
642  case dest_term t of
643    COMB (t1, t2) => let
644    in
645      case Lib.total beta_conv t of
646        NONE => let
647        in
648          case bn0 t1 of
649            NONE => Option.map (fn t2' => mk_comb (t1, t2')) (bn0 t2)
650          | SOME t1' => bn1 (mk_comb (t1', t2))
651        end
652      | SOME t' => bn1 t'
653    end
654  | LAMB (v, t) => Option.map (fn t' => mk_abs (v, t')) (bn0 t)
655  | x => NONE
656end
657
658fun beta_normalise t = case beta_normalise0 t of NONE => t | SOME x => x
659
660fun all_abconv [] [] = true
661  | all_abconv [] _ = false
662  | all_abconv _ [] = false
663  | all_abconv (h1::t1) (h2::t2) =
664     aconv (beta_normalise h1) (beta_normalise h2) andalso all_abconv t1 t2
665
666fun term_homatch tyavoids lconsts tyins (insts, homs) = let
667  (* local constants of both terms and types never change *)
668  val term_homatch = term_homatch tyavoids lconsts
669in
670  if null homs then insts
671  else let
672      val (env, ctm, vtm) = hd homs
673    in
674      if is_var vtm then
675        if aconv ctm vtm then term_homatch tyins (insts, tl homs)
676        else let
677            val newtyins =
678                tyenv_safe_insert (snd (dest_var vtm) |-> type_of ctm) tyins
679            val newinsts = (vtm |-> ctm)::insts
680          in
681            term_homatch newtyins (newinsts, tl homs)
682          end
683      else (* vtm not a var *) let
684          val (vhop, vargs) = strip_comb vtm
685          val afvs = free_varsl vargs
686          val inst_fn = Term.inst (fst tyins)
687        in
688          (let
689             val tmins =
690                 map (fn a =>
691                         (inst_fn a |->
692                                  (find_residue a env
693                                   handle NOT_FOUND =>
694                                          find_residue a insts
695                                   handle NOT_FOUND =>
696                                          if HOLset.member (lconsts, a)
697                                          then a
698                                          else failwith ""))) afvs
699             val pats0 = map inst_fn vargs
700             val pats = map (Term.subst tmins) pats0
701             val vhop' = inst_fn vhop
702             val ictm = list_mk_comb (vhop', pats)
703             val ni = let
704               val (chop, cargs) = strip_comb ctm
705             in
706               if all_abconv cargs pats then
707                 if aconv chop vhop then insts
708                 else safe_insert (vhop |-> chop) insts
709               else let
710                   val ginsts = map (fn p => (p |->
711                                                (if is_var p then p
712                                                 else genvar (type_of p))))
713                                    pats
714                   val ctm' = Term.subst ginsts ctm
715                   val gvs = map #residue ginsts
716                   val abstm = list_mk_abs (gvs, ctm')
717                   val vinsts = safe_insert (vhop |-> abstm) insts
718                   val icpair = (list_mk_comb (vhop', gvs) |-> ctm')
719                 in
720                   icpair::vinsts
721                 end
722             end
723           in
724             term_homatch tyins (ni, tl homs)
725           end) handle HOL_ERR _ => let
726                         val (lc, rc) = dest_comb ctm
727                         val (lv, rv) = dest_comb vtm
728                         val pinsts_homs' =
729                             term_pmatch lconsts env rv rc
730                                         (insts, (env, lc, lv)::(tl homs))
731                         val tyins' =
732                             get_type_insts tyavoids
733                                            (fst pinsts_homs')
734                                            ([], [])
735                       in
736                         term_homatch tyins' pinsts_homs'
737                       end
738        end
739    end
740end
741
742in
743
744fun ho_match_term0 tyavoids lconsts vtm ctm = let
745  val pinsts_homs = term_pmatch lconsts [] vtm ctm ([], [])
746  val tyins = get_type_insts tyavoids (fst pinsts_homs) ([], [])
747  val insts = term_homatch tyavoids lconsts tyins pinsts_homs
748in
749  separate_insts tyavoids insts
750end
751
752fun ho_match_term tyavoids lconsts vtm ctm = let
753  val (bcs, tmins, tyins) = ho_match_term0 tyavoids lconsts vtm ctm
754in
755  (tmins, #1 tyins)
756end handle e => raise (wrap_exn "HolKernel" "ho_match_term" e)
757
758end (* local *)
759
760val sort_vars =
761  Portable.pull_prefix o map (fn n => equal n o #1 o dest_var)
762
763end
764end
765