src/HOL/Library/old_recdef.ML
changeset 60520 09fc5eaa21ce
child 60521 52e956416fbf
equal deleted inserted replaced
60519:84b8e5c2580e 60520:09fc5eaa21ce
       
     1 (*  Title:      HOL/Tools/old_recdef.ML
       
     2     Author:     Konrad Slind, Cambridge University Computer Laboratory
       
     3     Author:     Lucas Dixon, University of Edinburgh
       
     4 
       
     5 Old TFL/recdef package.
       
     6 *)
       
     7 
       
     8 signature CASE_SPLIT =
       
     9 sig
       
    10   (* try to recursively split conjectured thm to given list of thms *)
       
    11   val splitto : Proof.context -> thm list -> thm -> thm
       
    12 end;
       
    13 
       
    14 signature UTILS =
       
    15 sig
       
    16   exception ERR of {module: string, func: string, mesg: string}
       
    17   val end_itlist: ('a -> 'a -> 'a) -> 'a list -> 'a
       
    18   val itlist2: ('a -> 'b -> 'c -> 'c) -> 'a list -> 'b list -> 'c -> 'c
       
    19   val pluck: ('a -> bool) -> 'a list -> 'a * 'a list
       
    20   val zip3: 'a list -> 'b list -> 'c list -> ('a*'b*'c) list
       
    21   val take: ('a -> 'b) -> int * 'a list -> 'b list
       
    22 end;
       
    23 
       
    24 signature USYNTAX =
       
    25 sig
       
    26   datatype lambda = VAR   of {Name : string, Ty : typ}
       
    27                   | CONST of {Name : string, Ty : typ}
       
    28                   | COMB  of {Rator: term, Rand : term}
       
    29                   | LAMB  of {Bvar : term, Body : term}
       
    30 
       
    31   val alpha : typ
       
    32 
       
    33   (* Types *)
       
    34   val type_vars  : typ -> typ list
       
    35   val type_varsl : typ list -> typ list
       
    36   val mk_vartype : string -> typ
       
    37   val is_vartype : typ -> bool
       
    38   val strip_prod_type : typ -> typ list
       
    39 
       
    40   (* Terms *)
       
    41   val free_vars_lr : term -> term list
       
    42   val type_vars_in_term : term -> typ list
       
    43   val dest_term  : term -> lambda
       
    44 
       
    45   (* Prelogic *)
       
    46   val inst      : (typ*typ) list -> term -> term
       
    47 
       
    48   (* Construction routines *)
       
    49   val mk_abs    :{Bvar  : term, Body : term} -> term
       
    50 
       
    51   val mk_imp    :{ant : term, conseq :  term} -> term
       
    52   val mk_select :{Bvar : term, Body : term} -> term
       
    53   val mk_forall :{Bvar : term, Body : term} -> term
       
    54   val mk_exists :{Bvar : term, Body : term} -> term
       
    55   val mk_conj   :{conj1 : term, conj2 : term} -> term
       
    56   val mk_disj   :{disj1 : term, disj2 : term} -> term
       
    57   val mk_pabs   :{varstruct : term, body : term} -> term
       
    58 
       
    59   (* Destruction routines *)
       
    60   val dest_const: term -> {Name : string, Ty : typ}
       
    61   val dest_comb : term -> {Rator : term, Rand : term}
       
    62   val dest_abs  : string list -> term -> {Bvar : term, Body : term} * string list
       
    63   val dest_eq     : term -> {lhs : term, rhs : term}
       
    64   val dest_imp    : term -> {ant : term, conseq : term}
       
    65   val dest_forall : term -> {Bvar : term, Body : term}
       
    66   val dest_exists : term -> {Bvar : term, Body : term}
       
    67   val dest_neg    : term -> term
       
    68   val dest_conj   : term -> {conj1 : term, conj2 : term}
       
    69   val dest_disj   : term -> {disj1 : term, disj2 : term}
       
    70   val dest_pair   : term -> {fst : term, snd : term}
       
    71   val dest_pabs   : string list -> term -> {varstruct : term, body : term, used : string list}
       
    72 
       
    73   val lhs   : term -> term
       
    74   val rhs   : term -> term
       
    75   val rand  : term -> term
       
    76 
       
    77   (* Query routines *)
       
    78   val is_imp    : term -> bool
       
    79   val is_forall : term -> bool
       
    80   val is_exists : term -> bool
       
    81   val is_neg    : term -> bool
       
    82   val is_conj   : term -> bool
       
    83   val is_disj   : term -> bool
       
    84   val is_pair   : term -> bool
       
    85   val is_pabs   : term -> bool
       
    86 
       
    87   (* Construction of a term from a list of Preterms *)
       
    88   val list_mk_abs    : (term list * term) -> term
       
    89   val list_mk_imp    : (term list * term) -> term
       
    90   val list_mk_forall : (term list * term) -> term
       
    91   val list_mk_conj   : term list -> term
       
    92 
       
    93   (* Destructing a term to a list of Preterms *)
       
    94   val strip_comb     : term -> (term * term list)
       
    95   val strip_abs      : term -> (term list * term)
       
    96   val strip_imp      : term -> (term list * term)
       
    97   val strip_forall   : term -> (term list * term)
       
    98   val strip_exists   : term -> (term list * term)
       
    99   val strip_disj     : term -> term list
       
   100 
       
   101   (* Miscellaneous *)
       
   102   val mk_vstruct : typ -> term list -> term
       
   103   val gen_all    : term -> term
       
   104   val find_term  : (term -> bool) -> term -> term option
       
   105   val dest_relation : term -> term * term * term
       
   106   val is_WFR : term -> bool
       
   107   val ARB : typ -> term
       
   108 end;
       
   109 
       
   110 signature DCTERM =
       
   111 sig
       
   112   val dest_comb: cterm -> cterm * cterm
       
   113   val dest_abs: string option -> cterm -> cterm * cterm
       
   114   val capply: cterm -> cterm -> cterm
       
   115   val cabs: cterm -> cterm -> cterm
       
   116   val mk_conj: cterm * cterm -> cterm
       
   117   val mk_disj: cterm * cterm -> cterm
       
   118   val mk_exists: cterm * cterm -> cterm
       
   119   val dest_conj: cterm -> cterm * cterm
       
   120   val dest_const: cterm -> {Name: string, Ty: typ}
       
   121   val dest_disj: cterm -> cterm * cterm
       
   122   val dest_eq: cterm -> cterm * cterm
       
   123   val dest_exists: cterm -> cterm * cterm
       
   124   val dest_forall: cterm -> cterm * cterm
       
   125   val dest_imp: cterm -> cterm * cterm
       
   126   val dest_neg: cterm -> cterm
       
   127   val dest_pair: cterm -> cterm * cterm
       
   128   val dest_var: cterm -> {Name:string, Ty:typ}
       
   129   val is_conj: cterm -> bool
       
   130   val is_disj: cterm -> bool
       
   131   val is_eq: cterm -> bool
       
   132   val is_exists: cterm -> bool
       
   133   val is_forall: cterm -> bool
       
   134   val is_imp: cterm -> bool
       
   135   val is_neg: cterm -> bool
       
   136   val is_pair: cterm -> bool
       
   137   val list_mk_disj: cterm list -> cterm
       
   138   val strip_abs: cterm -> cterm list * cterm
       
   139   val strip_comb: cterm -> cterm * cterm list
       
   140   val strip_disj: cterm -> cterm list
       
   141   val strip_exists: cterm -> cterm list * cterm
       
   142   val strip_forall: cterm -> cterm list * cterm
       
   143   val strip_imp: cterm -> cterm list * cterm
       
   144   val drop_prop: cterm -> cterm
       
   145   val mk_prop: cterm -> cterm
       
   146 end;
       
   147 
       
   148 signature RULES =
       
   149 sig
       
   150   val dest_thm: thm -> term list * term
       
   151 
       
   152   (* Inference rules *)
       
   153   val REFL: cterm -> thm
       
   154   val ASSUME: cterm -> thm
       
   155   val MP: thm -> thm -> thm
       
   156   val MATCH_MP: thm -> thm -> thm
       
   157   val CONJUNCT1: thm -> thm
       
   158   val CONJUNCT2: thm -> thm
       
   159   val CONJUNCTS: thm -> thm list
       
   160   val DISCH: cterm -> thm -> thm
       
   161   val UNDISCH: thm  -> thm
       
   162   val SPEC: cterm -> thm -> thm
       
   163   val ISPEC: cterm -> thm -> thm
       
   164   val ISPECL: cterm list -> thm -> thm
       
   165   val GEN: Proof.context -> cterm -> thm -> thm
       
   166   val GENL: Proof.context -> cterm list -> thm -> thm
       
   167   val LIST_CONJ: thm list -> thm
       
   168 
       
   169   val SYM: thm -> thm
       
   170   val DISCH_ALL: thm -> thm
       
   171   val FILTER_DISCH_ALL: (term -> bool) -> thm -> thm
       
   172   val SPEC_ALL: thm -> thm
       
   173   val GEN_ALL: Proof.context -> thm -> thm
       
   174   val IMP_TRANS: thm -> thm -> thm
       
   175   val PROVE_HYP: thm -> thm -> thm
       
   176 
       
   177   val CHOOSE: Proof.context -> cterm * thm -> thm -> thm
       
   178   val EXISTS: cterm * cterm -> thm -> thm
       
   179   val EXISTL: cterm list -> thm -> thm
       
   180   val IT_EXISTS: Proof.context -> (cterm * cterm) list -> thm -> thm
       
   181 
       
   182   val EVEN_ORS: thm list -> thm list
       
   183   val DISJ_CASESL: thm -> thm list -> thm
       
   184 
       
   185   val list_beta_conv: cterm -> cterm list -> thm
       
   186   val SUBS: Proof.context -> thm list -> thm -> thm
       
   187   val simpl_conv: Proof.context -> thm list -> cterm -> thm
       
   188 
       
   189   val rbeta: thm -> thm
       
   190   val tracing: bool Unsynchronized.ref
       
   191   val CONTEXT_REWRITE_RULE: Proof.context ->
       
   192     term * term list * thm * thm list -> thm -> thm * term list
       
   193   val RIGHT_ASSOC: Proof.context -> thm -> thm
       
   194 
       
   195   val prove: Proof.context -> bool -> term * tactic -> thm
       
   196 end;
       
   197 
       
   198 signature THRY =
       
   199 sig
       
   200   val match_term: theory -> term -> term -> (term * term) list * (typ * typ) list
       
   201   val match_type: theory -> typ -> typ -> (typ * typ) list
       
   202   val typecheck: theory -> term -> cterm
       
   203   (*datatype facts of various flavours*)
       
   204   val match_info: theory -> string -> {constructors: term list, case_const: term} option
       
   205   val induct_info: theory -> string -> {constructors: term list, nchotomy: thm} option
       
   206   val extract_info: theory -> {case_congs: thm list, case_rewrites: thm list}
       
   207 end;
       
   208 
       
   209 signature PRIM =
       
   210 sig
       
   211   val trace: bool Unsynchronized.ref
       
   212   val trace_thms: Proof.context -> string -> thm list -> unit
       
   213   val trace_cterm: Proof.context -> string -> cterm -> unit
       
   214   type pattern
       
   215   val mk_functional: theory -> term list -> {functional: term, pats: pattern list}
       
   216   val wfrec_definition0: string -> term -> term -> theory -> thm * theory
       
   217   val post_definition: Proof.context -> thm list -> thm * pattern list ->
       
   218    {rules: thm,
       
   219     rows: int list,
       
   220     TCs: term list list,
       
   221     full_pats_TCs: (term * term list) list}
       
   222   val wfrec_eqns: theory -> xstring -> thm list -> term list ->
       
   223    {WFR: term,
       
   224     SV: term list,
       
   225     proto_def: term,
       
   226     extracta: (thm * term list) list,
       
   227     pats: pattern list}
       
   228   val lazyR_def: theory -> xstring -> thm list -> term list ->
       
   229    {theory: theory,
       
   230     rules: thm,
       
   231     R: term,
       
   232     SV: term list,
       
   233     full_pats_TCs: (term * term list) list,
       
   234     patterns : pattern list}
       
   235   val mk_induction: theory ->
       
   236     {fconst: term, R: term, SV: term list, pat_TCs_list: (term * term list) list} -> thm
       
   237   val postprocess: Proof.context -> bool ->
       
   238     {wf_tac: tactic, terminator: tactic, simplifier: cterm -> thm} ->
       
   239     {rules: thm, induction: thm, TCs: term list list} ->
       
   240     {rules: thm, induction: thm, nested_tcs: thm list}
       
   241 end;
       
   242 
       
   243 signature TFL =
       
   244 sig
       
   245   val define_i: bool -> thm list -> thm list -> xstring -> term -> term list -> Proof.context ->
       
   246     {lhs: term, rules: (thm * int) list, induct: thm, tcs: term list} * Proof.context
       
   247   val define: bool -> thm list -> thm list -> xstring -> string -> string list -> Proof.context ->
       
   248     {lhs: term, rules: (thm * int) list, induct: thm, tcs: term list} * Proof.context
       
   249   val defer_i: thm list -> xstring -> term list -> theory -> thm * theory
       
   250   val defer: thm list -> xstring -> string list -> theory -> thm * theory
       
   251 end;
       
   252 
       
   253 signature OLD_RECDEF =
       
   254 sig
       
   255   val get_recdef: theory -> string
       
   256     -> {lhs: term, simps: thm list, rules: thm list list, induct: thm, tcs: term list} option
       
   257   val get_hints: Proof.context -> {simps: thm list, congs: (string * thm) list, wfs: thm list}
       
   258   val simp_add: attribute
       
   259   val simp_del: attribute
       
   260   val cong_add: attribute
       
   261   val cong_del: attribute
       
   262   val wf_add: attribute
       
   263   val wf_del: attribute
       
   264   val add_recdef: bool -> xstring -> string -> ((binding * string) * Token.src list) list ->
       
   265     Token.src option -> theory -> theory
       
   266       * {lhs: term, simps: thm list, rules: thm list list, induct: thm, tcs: term list}
       
   267   val add_recdef_i: bool -> xstring -> term -> ((binding * term) * attribute list) list ->
       
   268     theory -> theory * {lhs: term, simps: thm list, rules: thm list list, induct: thm, tcs: term list}
       
   269   val defer_recdef: xstring -> string list -> (Facts.ref * Token.src list) list
       
   270     -> theory -> theory * {induct_rules: thm}
       
   271   val defer_recdef_i: xstring -> term list -> thm list -> theory -> theory * {induct_rules: thm}
       
   272   val recdef_tc: bstring * Token.src list -> xstring -> int option -> bool ->
       
   273     local_theory -> Proof.state
       
   274   val recdef_tc_i: bstring * Token.src list -> string -> int option -> bool ->
       
   275     local_theory -> Proof.state
       
   276 end;
       
   277 
       
   278 structure Old_Recdef: OLD_RECDEF =
       
   279 struct
       
   280 
       
   281 (*** extra case splitting for TFL ***)
       
   282 
       
   283 structure CaseSplit: CASE_SPLIT =
       
   284 struct
       
   285 
       
   286 (* make a casethm from an induction thm *)
       
   287 val cases_thm_of_induct_thm =
       
   288      Seq.hd o (ALLGOALS (fn i => REPEAT (etac Drule.thin_rl i)));
       
   289 
       
   290 (* get the case_thm (my version) from a type *)
       
   291 fun case_thm_of_ty thy ty  =
       
   292     let
       
   293       val ty_str = case ty of
       
   294                      Type(ty_str, _) => ty_str
       
   295                    | TFree(s,_)  => error ("Free type: " ^ s)
       
   296                    | TVar((s,i),_) => error ("Free variable: " ^ s)
       
   297       val {induct, ...} = BNF_LFP_Compat.the_info thy [BNF_LFP_Compat.Keep_Nesting] ty_str
       
   298     in
       
   299       cases_thm_of_induct_thm induct
       
   300     end;
       
   301 
       
   302 
       
   303 (* for use when there are no prems to the subgoal *)
       
   304 (* does a case split on the given variable *)
       
   305 fun mk_casesplit_goal_thm ctxt (vstr,ty) gt =
       
   306     let
       
   307       val thy = Proof_Context.theory_of ctxt;
       
   308 
       
   309       val x = Free(vstr,ty);
       
   310       val abst = Abs(vstr, ty, Term.abstract_over (x, gt));
       
   311 
       
   312       val case_thm = case_thm_of_ty thy ty;
       
   313 
       
   314       val abs_ct = Thm.cterm_of ctxt abst;
       
   315       val free_ct = Thm.cterm_of ctxt x;
       
   316 
       
   317       val (Pv, Dv, type_insts) =
       
   318           case (Thm.concl_of case_thm) of
       
   319             (_ $ (Pv $ (Dv as Var(D, Dty)))) =>
       
   320             (Pv, Dv,
       
   321              Sign.typ_match thy (Dty, ty) Vartab.empty)
       
   322           | _ => error "not a valid case thm";
       
   323       val type_cinsts = map (fn (ixn, (S, T)) => apply2 (Thm.ctyp_of ctxt) (TVar (ixn, S), T))
       
   324         (Vartab.dest type_insts);
       
   325       val cPv = Thm.cterm_of ctxt (Envir.subst_term_types type_insts Pv);
       
   326       val cDv = Thm.cterm_of ctxt (Envir.subst_term_types type_insts Dv);
       
   327     in
       
   328       Conv.fconv_rule Drule.beta_eta_conversion
       
   329          (case_thm
       
   330             |> Thm.instantiate (type_cinsts, [])
       
   331             |> Thm.instantiate ([], [(cPv, abs_ct), (cDv, free_ct)]))
       
   332     end;
       
   333 
       
   334 
       
   335 (* the find_XXX_split functions are simply doing a lightwieght (I
       
   336 think) term matching equivalent to find where to do the next split *)
       
   337 
       
   338 (* assuming two twems are identical except for a free in one at a
       
   339 subterm, or constant in another, ie assume that one term is a plit of
       
   340 another, then gives back the free variable that has been split. *)
       
   341 exception find_split_exp of string
       
   342 fun find_term_split (Free v, _ $ _) = SOME v
       
   343   | find_term_split (Free v, Const _) = SOME v
       
   344   | find_term_split (Free v, Abs _) = SOME v (* do we really want this case? *)
       
   345   | find_term_split (Free v, Var _) = NONE (* keep searching *)
       
   346   | find_term_split (a $ b, a2 $ b2) =
       
   347     (case find_term_split (a, a2) of
       
   348        NONE => find_term_split (b,b2)
       
   349      | vopt => vopt)
       
   350   | find_term_split (Abs(_,ty,t1), Abs(_,ty2,t2)) =
       
   351     find_term_split (t1, t2)
       
   352   | find_term_split (Const (x,ty), Const(x2,ty2)) =
       
   353     if x = x2 then NONE else (* keep searching *)
       
   354     raise find_split_exp (* stop now *)
       
   355             "Terms are not identical upto a free varaible! (Consts)"
       
   356   | find_term_split (Bound i, Bound j) =
       
   357     if i = j then NONE else (* keep searching *)
       
   358     raise find_split_exp (* stop now *)
       
   359             "Terms are not identical upto a free varaible! (Bound)"
       
   360   | find_term_split _ =
       
   361     raise find_split_exp (* stop now *)
       
   362             "Terms are not identical upto a free varaible! (Other)";
       
   363 
       
   364 (* assume that "splitth" is a case split form of subgoal i of "genth",
       
   365 then look for a free variable to split, breaking the subgoal closer to
       
   366 splitth. *)
       
   367 fun find_thm_split splitth i genth =
       
   368     find_term_split (Logic.get_goal (Thm.prop_of genth) i,
       
   369                      Thm.concl_of splitth) handle find_split_exp _ => NONE;
       
   370 
       
   371 (* as above but searches "splitths" for a theorem that suggest a case split *)
       
   372 fun find_thms_split splitths i genth =
       
   373     Library.get_first (fn sth => find_thm_split sth i genth) splitths;
       
   374 
       
   375 
       
   376 (* split the subgoal i of "genth" until we get to a member of
       
   377 splitths. Assumes that genth will be a general form of splitths, that
       
   378 can be case-split, as needed. Otherwise fails. Note: We assume that
       
   379 all of "splitths" are split to the same level, and thus it doesn't
       
   380 matter which one we choose to look for the next split. Simply add
       
   381 search on splitthms and split variable, to change this.  *)
       
   382 (* Note: possible efficiency measure: when a case theorem is no longer
       
   383 useful, drop it? *)
       
   384 (* Note: This should not be a separate tactic but integrated into the
       
   385 case split done during recdef's case analysis, this would avoid us
       
   386 having to (re)search for variables to split. *)
       
   387 fun splitto ctxt splitths genth =
       
   388     let
       
   389       val _ = not (null splitths) orelse error "splitto: no given splitths";
       
   390 
       
   391       (* check if we are a member of splitths - FIXME: quicker and
       
   392       more flexible with discrim net. *)
       
   393       fun solve_by_splitth th split =
       
   394         Thm.biresolution (SOME ctxt) false [(false,split)] 1 th;
       
   395 
       
   396       fun split th =
       
   397         (case find_thms_split splitths 1 th of
       
   398           NONE =>
       
   399            (writeln (cat_lines
       
   400             (["th:", Display.string_of_thm ctxt th, "split ths:"] @
       
   401               map (Display.string_of_thm ctxt) splitths @ ["\n--"]));
       
   402             error "splitto: cannot find variable to split on")
       
   403         | SOME v =>
       
   404             let
       
   405               val gt = HOLogic.dest_Trueprop (#1 (Logic.dest_implies (Thm.prop_of th)));
       
   406               val split_thm = mk_casesplit_goal_thm ctxt v gt;
       
   407               val (subthms, expf) = IsaND.fixed_subgoal_thms ctxt split_thm;
       
   408             in
       
   409               expf (map recsplitf subthms)
       
   410             end)
       
   411 
       
   412       and recsplitf th =
       
   413         (* note: multiple unifiers! we only take the first element,
       
   414            probably fine -- there is probably only one anyway. *)
       
   415         (case get_first (Seq.pull o solve_by_splitth th) splitths of
       
   416           NONE => split th
       
   417         | SOME (solved_th, _) => solved_th);
       
   418     in
       
   419       recsplitf genth
       
   420     end;
       
   421 
       
   422 end;
       
   423 
       
   424 
       
   425 (*** basic utilities ***)
       
   426 
       
   427 structure Utils: UTILS =
       
   428 struct
       
   429 
       
   430 (*standard exception for TFL*)
       
   431 exception ERR of {module: string, func: string, mesg: string};
       
   432 
       
   433 fun UTILS_ERR func mesg = ERR {module = "Utils", func = func, mesg = mesg};
       
   434 
       
   435 
       
   436 fun end_itlist f [] = raise (UTILS_ERR "end_itlist" "list too short")
       
   437   | end_itlist f [x] = x
       
   438   | end_itlist f (x :: xs) = f x (end_itlist f xs);
       
   439 
       
   440 fun itlist2 f L1 L2 base_value =
       
   441  let fun it ([],[]) = base_value
       
   442        | it ((a::rst1),(b::rst2)) = f a b (it (rst1,rst2))
       
   443        | it _ = raise UTILS_ERR "itlist2" "different length lists"
       
   444  in  it (L1,L2)
       
   445  end;
       
   446 
       
   447 fun pluck p  =
       
   448   let fun remv ([],_) = raise UTILS_ERR "pluck" "item not found"
       
   449         | remv (h::t, A) = if p h then (h, rev A @ t) else remv (t,h::A)
       
   450   in fn L => remv(L,[])
       
   451   end;
       
   452 
       
   453 fun take f =
       
   454   let fun grab(0,L) = []
       
   455         | grab(n, x::rst) = f x::grab(n-1,rst)
       
   456   in grab
       
   457   end;
       
   458 
       
   459 fun zip3 [][][] = []
       
   460   | zip3 (x::l1) (y::l2) (z::l3) = (x,y,z)::zip3 l1 l2 l3
       
   461   | zip3 _ _ _ = raise UTILS_ERR "zip3" "different lengths";
       
   462 
       
   463 
       
   464 end;
       
   465 
       
   466 
       
   467 (*** emulation of HOL's abstract syntax functions ***)
       
   468 
       
   469 structure USyntax: USYNTAX =
       
   470 struct
       
   471 
       
   472 infix 4 ##;
       
   473 
       
   474 fun USYN_ERR func mesg = Utils.ERR {module = "USyntax", func = func, mesg = mesg};
       
   475 
       
   476 
       
   477 (*---------------------------------------------------------------------------
       
   478  *
       
   479  *                            Types
       
   480  *
       
   481  *---------------------------------------------------------------------------*)
       
   482 val mk_prim_vartype = TVar;
       
   483 fun mk_vartype s = mk_prim_vartype ((s, 0), @{sort type});
       
   484 
       
   485 (* But internally, it's useful *)
       
   486 fun dest_vtype (TVar x) = x
       
   487   | dest_vtype _ = raise USYN_ERR "dest_vtype" "not a flexible type variable";
       
   488 
       
   489 val is_vartype = can dest_vtype;
       
   490 
       
   491 val type_vars  = map mk_prim_vartype o Misc_Legacy.typ_tvars
       
   492 fun type_varsl L = distinct (op =) (fold (curry op @ o type_vars) L []);
       
   493 
       
   494 val alpha  = mk_vartype "'a"
       
   495 val beta   = mk_vartype "'b"
       
   496 
       
   497 val strip_prod_type = HOLogic.flatten_tupleT;
       
   498 
       
   499 
       
   500 
       
   501 (*---------------------------------------------------------------------------
       
   502  *
       
   503  *                              Terms
       
   504  *
       
   505  *---------------------------------------------------------------------------*)
       
   506 
       
   507 (* Free variables, in order of occurrence, from left to right in the
       
   508  * syntax tree. *)
       
   509 fun free_vars_lr tm =
       
   510   let fun memb x = let fun m[] = false | m(y::rst) = (x=y)orelse m rst in m end
       
   511       fun add (t, frees) = case t of
       
   512             Free   _ => if (memb t frees) then frees else t::frees
       
   513           | Abs (_,_,body) => add(body,frees)
       
   514           | f$t =>  add(t, add(f, frees))
       
   515           | _ => frees
       
   516   in rev(add(tm,[]))
       
   517   end;
       
   518 
       
   519 
       
   520 
       
   521 val type_vars_in_term = map mk_prim_vartype o Misc_Legacy.term_tvars;
       
   522 
       
   523 
       
   524 
       
   525 (* Prelogic *)
       
   526 fun dest_tybinding (v,ty) = (#1(dest_vtype v),ty)
       
   527 fun inst theta = subst_vars (map dest_tybinding theta,[])
       
   528 
       
   529 
       
   530 (* Construction routines *)
       
   531 
       
   532 fun mk_abs{Bvar as Var((s,_),ty),Body}  = Abs(s,ty,abstract_over(Bvar,Body))
       
   533   | mk_abs{Bvar as Free(s,ty),Body}  = Abs(s,ty,abstract_over(Bvar,Body))
       
   534   | mk_abs _ = raise USYN_ERR "mk_abs" "Bvar is not a variable";
       
   535 
       
   536 
       
   537 fun mk_imp{ant,conseq} =
       
   538    let val c = Const(@{const_name HOL.implies},HOLogic.boolT --> HOLogic.boolT --> HOLogic.boolT)
       
   539    in list_comb(c,[ant,conseq])
       
   540    end;
       
   541 
       
   542 fun mk_select (r as {Bvar,Body}) =
       
   543   let val ty = type_of Bvar
       
   544       val c = Const(@{const_name Eps},(ty --> HOLogic.boolT) --> ty)
       
   545   in list_comb(c,[mk_abs r])
       
   546   end;
       
   547 
       
   548 fun mk_forall (r as {Bvar,Body}) =
       
   549   let val ty = type_of Bvar
       
   550       val c = Const(@{const_name All},(ty --> HOLogic.boolT) --> HOLogic.boolT)
       
   551   in list_comb(c,[mk_abs r])
       
   552   end;
       
   553 
       
   554 fun mk_exists (r as {Bvar,Body}) =
       
   555   let val ty = type_of Bvar
       
   556       val c = Const(@{const_name Ex},(ty --> HOLogic.boolT) --> HOLogic.boolT)
       
   557   in list_comb(c,[mk_abs r])
       
   558   end;
       
   559 
       
   560 
       
   561 fun mk_conj{conj1,conj2} =
       
   562    let val c = Const(@{const_name HOL.conj},HOLogic.boolT --> HOLogic.boolT --> HOLogic.boolT)
       
   563    in list_comb(c,[conj1,conj2])
       
   564    end;
       
   565 
       
   566 fun mk_disj{disj1,disj2} =
       
   567    let val c = Const(@{const_name HOL.disj},HOLogic.boolT --> HOLogic.boolT --> HOLogic.boolT)
       
   568    in list_comb(c,[disj1,disj2])
       
   569    end;
       
   570 
       
   571 fun prod_ty ty1 ty2 = HOLogic.mk_prodT (ty1,ty2);
       
   572 
       
   573 local
       
   574 fun mk_uncurry (xt, yt, zt) =
       
   575     Const(@{const_name case_prod}, (xt --> yt --> zt) --> prod_ty xt yt --> zt)
       
   576 fun dest_pair(Const(@{const_name Pair},_) $ M $ N) = {fst=M, snd=N}
       
   577   | dest_pair _ = raise USYN_ERR "dest_pair" "not a pair"
       
   578 fun is_var (Var _) = true | is_var (Free _) = true | is_var _ = false
       
   579 in
       
   580 fun mk_pabs{varstruct,body} =
       
   581  let fun mpa (varstruct, body) =
       
   582        if is_var varstruct
       
   583        then mk_abs {Bvar = varstruct, Body = body}
       
   584        else let val {fst, snd} = dest_pair varstruct
       
   585             in mk_uncurry (type_of fst, type_of snd, type_of body) $
       
   586                mpa (fst, mpa (snd, body))
       
   587             end
       
   588  in mpa (varstruct, body) end
       
   589  handle TYPE _ => raise USYN_ERR "mk_pabs" "";
       
   590 end;
       
   591 
       
   592 (* Destruction routines *)
       
   593 
       
   594 datatype lambda = VAR   of {Name : string, Ty : typ}
       
   595                 | CONST of {Name : string, Ty : typ}
       
   596                 | COMB  of {Rator: term, Rand : term}
       
   597                 | LAMB  of {Bvar : term, Body : term};
       
   598 
       
   599 
       
   600 fun dest_term(Var((s,i),ty)) = VAR{Name = s, Ty = ty}
       
   601   | dest_term(Free(s,ty))    = VAR{Name = s, Ty = ty}
       
   602   | dest_term(Const(s,ty))   = CONST{Name = s, Ty = ty}
       
   603   | dest_term(M$N)           = COMB{Rator=M,Rand=N}
       
   604   | dest_term(Abs(s,ty,M))   = let  val v = Free(s,ty)
       
   605                                in LAMB{Bvar = v, Body = Term.betapply (M,v)}
       
   606                                end
       
   607   | dest_term(Bound _)       = raise USYN_ERR "dest_term" "Bound";
       
   608 
       
   609 fun dest_const(Const(s,ty)) = {Name = s, Ty = ty}
       
   610   | dest_const _ = raise USYN_ERR "dest_const" "not a constant";
       
   611 
       
   612 fun dest_comb(t1 $ t2) = {Rator = t1, Rand = t2}
       
   613   | dest_comb _ =  raise USYN_ERR "dest_comb" "not a comb";
       
   614 
       
   615 fun dest_abs used (a as Abs(s, ty, M)) =
       
   616      let
       
   617        val s' = singleton (Name.variant_list used) s;
       
   618        val v = Free(s', ty);
       
   619      in ({Bvar = v, Body = Term.betapply (a,v)}, s'::used)
       
   620      end
       
   621   | dest_abs _ _ =  raise USYN_ERR "dest_abs" "not an abstraction";
       
   622 
       
   623 fun dest_eq(Const(@{const_name HOL.eq},_) $ M $ N) = {lhs=M, rhs=N}
       
   624   | dest_eq _ = raise USYN_ERR "dest_eq" "not an equality";
       
   625 
       
   626 fun dest_imp(Const(@{const_name HOL.implies},_) $ M $ N) = {ant=M, conseq=N}
       
   627   | dest_imp _ = raise USYN_ERR "dest_imp" "not an implication";
       
   628 
       
   629 fun dest_forall(Const(@{const_name All},_) $ (a as Abs _)) = fst (dest_abs [] a)
       
   630   | dest_forall _ = raise USYN_ERR "dest_forall" "not a forall";
       
   631 
       
   632 fun dest_exists(Const(@{const_name Ex},_) $ (a as Abs _)) = fst (dest_abs [] a)
       
   633   | dest_exists _ = raise USYN_ERR "dest_exists" "not an existential";
       
   634 
       
   635 fun dest_neg(Const(@{const_name Not},_) $ M) = M
       
   636   | dest_neg _ = raise USYN_ERR "dest_neg" "not a negation";
       
   637 
       
   638 fun dest_conj(Const(@{const_name HOL.conj},_) $ M $ N) = {conj1=M, conj2=N}
       
   639   | dest_conj _ = raise USYN_ERR "dest_conj" "not a conjunction";
       
   640 
       
   641 fun dest_disj(Const(@{const_name HOL.disj},_) $ M $ N) = {disj1=M, disj2=N}
       
   642   | dest_disj _ = raise USYN_ERR "dest_disj" "not a disjunction";
       
   643 
       
   644 fun mk_pair{fst,snd} =
       
   645    let val ty1 = type_of fst
       
   646        val ty2 = type_of snd
       
   647        val c = Const(@{const_name Pair},ty1 --> ty2 --> prod_ty ty1 ty2)
       
   648    in list_comb(c,[fst,snd])
       
   649    end;
       
   650 
       
   651 fun dest_pair(Const(@{const_name Pair},_) $ M $ N) = {fst=M, snd=N}
       
   652   | dest_pair _ = raise USYN_ERR "dest_pair" "not a pair";
       
   653 
       
   654 
       
   655 local  fun ucheck t = (if #Name (dest_const t) = @{const_name case_prod} then t
       
   656                        else raise Match)
       
   657 in
       
   658 fun dest_pabs used tm =
       
   659    let val ({Bvar,Body}, used') = dest_abs used tm
       
   660    in {varstruct = Bvar, body = Body, used = used'}
       
   661    end handle Utils.ERR _ =>
       
   662           let val {Rator,Rand} = dest_comb tm
       
   663               val _ = ucheck Rator
       
   664               val {varstruct = lv, body, used = used'} = dest_pabs used Rand
       
   665               val {varstruct = rv, body, used = used''} = dest_pabs used' body
       
   666           in {varstruct = mk_pair {fst = lv, snd = rv}, body = body, used = used''}
       
   667           end
       
   668 end;
       
   669 
       
   670 
       
   671 val lhs   = #lhs o dest_eq
       
   672 val rhs   = #rhs o dest_eq
       
   673 val rand  = #Rand o dest_comb
       
   674 
       
   675 
       
   676 (* Query routines *)
       
   677 val is_imp    = can dest_imp
       
   678 val is_forall = can dest_forall
       
   679 val is_exists = can dest_exists
       
   680 val is_neg    = can dest_neg
       
   681 val is_conj   = can dest_conj
       
   682 val is_disj   = can dest_disj
       
   683 val is_pair   = can dest_pair
       
   684 val is_pabs   = can (dest_pabs [])
       
   685 
       
   686 
       
   687 (* Construction of a cterm from a list of Terms *)
       
   688 
       
   689 fun list_mk_abs(L,tm) = fold_rev (fn v => fn M => mk_abs{Bvar=v, Body=M}) L tm;
       
   690 
       
   691 (* These others are almost never used *)
       
   692 fun list_mk_imp(A,c) = fold_rev (fn a => fn tm => mk_imp{ant=a,conseq=tm}) A c;
       
   693 fun list_mk_forall(V,t) = fold_rev (fn v => fn b => mk_forall{Bvar=v, Body=b})V t;
       
   694 val list_mk_conj = Utils.end_itlist(fn c1 => fn tm => mk_conj{conj1=c1, conj2=tm})
       
   695 
       
   696 
       
   697 (* Need to reverse? *)
       
   698 fun gen_all tm = list_mk_forall(Misc_Legacy.term_frees tm, tm);
       
   699 
       
   700 (* Destructing a cterm to a list of Terms *)
       
   701 fun strip_comb tm =
       
   702    let fun dest(M$N, A) = dest(M, N::A)
       
   703          | dest x = x
       
   704    in dest(tm,[])
       
   705    end;
       
   706 
       
   707 fun strip_abs(tm as Abs _) =
       
   708        let val ({Bvar,Body}, _) = dest_abs [] tm
       
   709            val (bvs, core) = strip_abs Body
       
   710        in (Bvar::bvs, core)
       
   711        end
       
   712   | strip_abs M = ([],M);
       
   713 
       
   714 
       
   715 fun strip_imp fm =
       
   716    if (is_imp fm)
       
   717    then let val {ant,conseq} = dest_imp fm
       
   718             val (was,wb) = strip_imp conseq
       
   719         in ((ant::was), wb)
       
   720         end
       
   721    else ([],fm);
       
   722 
       
   723 fun strip_forall fm =
       
   724    if (is_forall fm)
       
   725    then let val {Bvar,Body} = dest_forall fm
       
   726             val (bvs,core) = strip_forall Body
       
   727         in ((Bvar::bvs), core)
       
   728         end
       
   729    else ([],fm);
       
   730 
       
   731 
       
   732 fun strip_exists fm =
       
   733    if (is_exists fm)
       
   734    then let val {Bvar, Body} = dest_exists fm
       
   735             val (bvs,core) = strip_exists Body
       
   736         in (Bvar::bvs, core)
       
   737         end
       
   738    else ([],fm);
       
   739 
       
   740 fun strip_disj w =
       
   741    if (is_disj w)
       
   742    then let val {disj1,disj2} = dest_disj w
       
   743         in (strip_disj disj1@strip_disj disj2)
       
   744         end
       
   745    else [w];
       
   746 
       
   747 
       
   748 (* Miscellaneous *)
       
   749 
       
   750 fun mk_vstruct ty V =
       
   751   let fun follow_prod_type (Type(@{type_name Product_Type.prod},[ty1,ty2])) vs =
       
   752               let val (ltm,vs1) = follow_prod_type ty1 vs
       
   753                   val (rtm,vs2) = follow_prod_type ty2 vs1
       
   754               in (mk_pair{fst=ltm, snd=rtm}, vs2) end
       
   755         | follow_prod_type _ (v::vs) = (v,vs)
       
   756   in #1 (follow_prod_type ty V)  end;
       
   757 
       
   758 
       
   759 (* Search a term for a sub-term satisfying the predicate p. *)
       
   760 fun find_term p =
       
   761    let fun find tm =
       
   762       if (p tm) then SOME tm
       
   763       else case tm of
       
   764           Abs(_,_,body) => find body
       
   765         | (t$u)         => (case find t of NONE => find u | some => some)
       
   766         | _             => NONE
       
   767    in find
       
   768    end;
       
   769 
       
   770 fun dest_relation tm =
       
   771    if (type_of tm = HOLogic.boolT)
       
   772    then let val (Const(@{const_name Set.member},_) $ (Const(@{const_name Pair},_)$y$x) $ R) = tm
       
   773         in (R,y,x)
       
   774         end handle Bind => raise USYN_ERR "dest_relation" "unexpected term structure"
       
   775    else raise USYN_ERR "dest_relation" "not a boolean term";
       
   776 
       
   777 fun is_WFR (Const(@{const_name Wellfounded.wf},_)$_) = true
       
   778   | is_WFR _                 = false;
       
   779 
       
   780 fun ARB ty = mk_select{Bvar=Free("v",ty),
       
   781                        Body=Const(@{const_name True},HOLogic.boolT)};
       
   782 
       
   783 end;
       
   784 
       
   785 
       
   786 (*** derived cterm destructors ***)
       
   787 
       
   788 structure Dcterm: DCTERM =
       
   789 struct
       
   790 
       
   791 fun ERR func mesg = Utils.ERR {module = "Dcterm", func = func, mesg = mesg};
       
   792 
       
   793 
       
   794 fun dest_comb t = Thm.dest_comb t
       
   795   handle CTERM (msg, _) => raise ERR "dest_comb" msg;
       
   796 
       
   797 fun dest_abs a t = Thm.dest_abs a t
       
   798   handle CTERM (msg, _) => raise ERR "dest_abs" msg;
       
   799 
       
   800 fun capply t u = Thm.apply t u
       
   801   handle CTERM (msg, _) => raise ERR "capply" msg;
       
   802 
       
   803 fun cabs a t = Thm.lambda a t
       
   804   handle CTERM (msg, _) => raise ERR "cabs" msg;
       
   805 
       
   806 
       
   807 (*---------------------------------------------------------------------------
       
   808  * Some simple constructor functions.
       
   809  *---------------------------------------------------------------------------*)
       
   810 
       
   811 val mk_hol_const = Thm.cterm_of @{theory_context HOL} o Const;
       
   812 
       
   813 fun mk_exists (r as (Bvar, Body)) =
       
   814   let val ty = Thm.typ_of_cterm Bvar
       
   815       val c = mk_hol_const(@{const_name Ex}, (ty --> HOLogic.boolT) --> HOLogic.boolT)
       
   816   in capply c (uncurry cabs r) end;
       
   817 
       
   818 
       
   819 local val c = mk_hol_const(@{const_name HOL.conj}, HOLogic.boolT --> HOLogic.boolT --> HOLogic.boolT)
       
   820 in fun mk_conj(conj1,conj2) = capply (capply c conj1) conj2
       
   821 end;
       
   822 
       
   823 local val c = mk_hol_const(@{const_name HOL.disj}, HOLogic.boolT --> HOLogic.boolT --> HOLogic.boolT)
       
   824 in fun mk_disj(disj1,disj2) = capply (capply c disj1) disj2
       
   825 end;
       
   826 
       
   827 
       
   828 (*---------------------------------------------------------------------------
       
   829  * The primitives.
       
   830  *---------------------------------------------------------------------------*)
       
   831 fun dest_const ctm =
       
   832    (case Thm.term_of ctm
       
   833       of Const(s,ty) => {Name = s, Ty = ty}
       
   834        | _ => raise ERR "dest_const" "not a constant");
       
   835 
       
   836 fun dest_var ctm =
       
   837    (case Thm.term_of ctm
       
   838       of Var((s,i),ty) => {Name=s, Ty=ty}
       
   839        | Free(s,ty)    => {Name=s, Ty=ty}
       
   840        |             _ => raise ERR "dest_var" "not a variable");
       
   841 
       
   842 
       
   843 (*---------------------------------------------------------------------------
       
   844  * Derived destructor operations.
       
   845  *---------------------------------------------------------------------------*)
       
   846 
       
   847 fun dest_monop expected tm =
       
   848  let
       
   849    fun err () = raise ERR "dest_monop" ("Not a(n) " ^ quote expected);
       
   850    val (c, N) = dest_comb tm handle Utils.ERR _ => err ();
       
   851    val name = #Name (dest_const c handle Utils.ERR _ => err ());
       
   852  in if name = expected then N else err () end;
       
   853 
       
   854 fun dest_binop expected tm =
       
   855  let
       
   856    fun err () = raise ERR "dest_binop" ("Not a(n) " ^ quote expected);
       
   857    val (M, N) = dest_comb tm handle Utils.ERR _ => err ()
       
   858  in (dest_monop expected M, N) handle Utils.ERR _ => err () end;
       
   859 
       
   860 fun dest_binder expected tm =
       
   861   dest_abs NONE (dest_monop expected tm)
       
   862   handle Utils.ERR _ => raise ERR "dest_binder" ("Not a(n) " ^ quote expected);
       
   863 
       
   864 
       
   865 val dest_neg    = dest_monop @{const_name Not}
       
   866 val dest_pair   = dest_binop @{const_name Pair}
       
   867 val dest_eq     = dest_binop @{const_name HOL.eq}
       
   868 val dest_imp    = dest_binop @{const_name HOL.implies}
       
   869 val dest_conj   = dest_binop @{const_name HOL.conj}
       
   870 val dest_disj   = dest_binop @{const_name HOL.disj}
       
   871 val dest_select = dest_binder @{const_name Eps}
       
   872 val dest_exists = dest_binder @{const_name Ex}
       
   873 val dest_forall = dest_binder @{const_name All}
       
   874 
       
   875 (* Query routines *)
       
   876 
       
   877 val is_eq     = can dest_eq
       
   878 val is_imp    = can dest_imp
       
   879 val is_select = can dest_select
       
   880 val is_forall = can dest_forall
       
   881 val is_exists = can dest_exists
       
   882 val is_neg    = can dest_neg
       
   883 val is_conj   = can dest_conj
       
   884 val is_disj   = can dest_disj
       
   885 val is_pair   = can dest_pair
       
   886 
       
   887 
       
   888 (*---------------------------------------------------------------------------
       
   889  * Iterated creation.
       
   890  *---------------------------------------------------------------------------*)
       
   891 val list_mk_disj = Utils.end_itlist (fn d1 => fn tm => mk_disj (d1, tm));
       
   892 
       
   893 (*---------------------------------------------------------------------------
       
   894  * Iterated destruction. (To the "right" in a term.)
       
   895  *---------------------------------------------------------------------------*)
       
   896 fun strip break tm =
       
   897   let fun dest (p as (ctm,accum)) =
       
   898         let val (M,N) = break ctm
       
   899         in dest (N, M::accum)
       
   900         end handle Utils.ERR _ => p
       
   901   in dest (tm,[])
       
   902   end;
       
   903 
       
   904 fun rev2swap (x,l) = (rev l, x);
       
   905 
       
   906 val strip_comb   = strip (Library.swap o dest_comb)  (* Goes to the "left" *)
       
   907 val strip_imp    = rev2swap o strip dest_imp
       
   908 val strip_abs    = rev2swap o strip (dest_abs NONE)
       
   909 val strip_forall = rev2swap o strip dest_forall
       
   910 val strip_exists = rev2swap o strip dest_exists
       
   911 
       
   912 val strip_disj   = rev o (op::) o strip dest_disj
       
   913 
       
   914 
       
   915 (*---------------------------------------------------------------------------
       
   916  * Going into and out of prop
       
   917  *---------------------------------------------------------------------------*)
       
   918 
       
   919 fun is_Trueprop ct =
       
   920   (case Thm.term_of ct of
       
   921     Const (@{const_name Trueprop}, _) $ _ => true
       
   922   | _ => false);
       
   923 
       
   924 fun mk_prop ct = if is_Trueprop ct then ct else Thm.apply @{cterm Trueprop} ct;
       
   925 fun drop_prop ct = if is_Trueprop ct then Thm.dest_arg ct else ct;
       
   926 
       
   927 end;
       
   928 
       
   929 
       
   930 (*** notable theorems ***)
       
   931 
       
   932 structure Thms =
       
   933 struct
       
   934   val WFREC_COROLLARY = @{thm tfl_wfrec};
       
   935   val WF_INDUCTION_THM = @{thm tfl_wf_induct};
       
   936   val CUT_DEF = @{thm tfl_cut_def};
       
   937   val eqT = @{thm tfl_eq_True};
       
   938   val rev_eq_mp = @{thm tfl_rev_eq_mp};
       
   939   val simp_thm = @{thm tfl_simp_thm};
       
   940   val P_imp_P_iff_True = @{thm tfl_P_imp_P_iff_True};
       
   941   val imp_trans = @{thm tfl_imp_trans};
       
   942   val disj_assoc = @{thm tfl_disj_assoc};
       
   943   val tfl_disjE = @{thm tfl_disjE};
       
   944   val choose_thm = @{thm tfl_exE};
       
   945 end;
       
   946 
       
   947 
       
   948 (*** emulation of HOL inference rules for TFL ***)
       
   949 
       
   950 structure Rules: RULES =
       
   951 struct
       
   952 
       
   953 fun RULES_ERR func mesg = Utils.ERR {module = "Rules", func = func, mesg = mesg};
       
   954 
       
   955 
       
   956 fun cconcl thm = Dcterm.drop_prop (#prop (Thm.crep_thm thm));
       
   957 fun chyps thm = map Dcterm.drop_prop (#hyps (Thm.crep_thm thm));
       
   958 
       
   959 fun dest_thm thm =
       
   960   let val {prop,hyps,...} = Thm.rep_thm thm
       
   961   in (map HOLogic.dest_Trueprop hyps, HOLogic.dest_Trueprop prop) end
       
   962   handle TERM _ => raise RULES_ERR "dest_thm" "missing Trueprop";
       
   963 
       
   964 
       
   965 (* Inference rules *)
       
   966 
       
   967 (*---------------------------------------------------------------------------
       
   968  *        Equality (one step)
       
   969  *---------------------------------------------------------------------------*)
       
   970 
       
   971 fun REFL tm = Thm.reflexive tm RS meta_eq_to_obj_eq
       
   972   handle THM (msg, _, _) => raise RULES_ERR "REFL" msg;
       
   973 
       
   974 fun SYM thm = thm RS sym
       
   975   handle THM (msg, _, _) => raise RULES_ERR "SYM" msg;
       
   976 
       
   977 fun ALPHA thm ctm1 =
       
   978   let
       
   979     val ctm2 = Thm.cprop_of thm;
       
   980     val ctm2_eq = Thm.reflexive ctm2;
       
   981     val ctm1_eq = Thm.reflexive ctm1;
       
   982   in Thm.equal_elim (Thm.transitive ctm2_eq ctm1_eq) thm end
       
   983   handle THM (msg, _, _) => raise RULES_ERR "ALPHA" msg;
       
   984 
       
   985 fun rbeta th =
       
   986   (case Dcterm.strip_comb (cconcl th) of
       
   987     (_, [l, r]) => Thm.transitive th (Thm.beta_conversion false r)
       
   988   | _ => raise RULES_ERR "rbeta" "");
       
   989 
       
   990 
       
   991 (*----------------------------------------------------------------------------
       
   992  *        Implication and the assumption list
       
   993  *
       
   994  * Assumptions get stuck on the meta-language assumption list. Implications
       
   995  * are in the object language, so discharging an assumption "A" from theorem
       
   996  * "B" results in something that looks like "A --> B".
       
   997  *---------------------------------------------------------------------------*)
       
   998 
       
   999 fun ASSUME ctm = Thm.assume (Dcterm.mk_prop ctm);
       
  1000 
       
  1001 
       
  1002 (*---------------------------------------------------------------------------
       
  1003  * Implication in TFL is -->. Meta-language implication (==>) is only used
       
  1004  * in the implementation of some of the inference rules below.
       
  1005  *---------------------------------------------------------------------------*)
       
  1006 fun MP th1 th2 = th2 RS (th1 RS mp)
       
  1007   handle THM (msg, _, _) => raise RULES_ERR "MP" msg;
       
  1008 
       
  1009 (*forces the first argument to be a proposition if necessary*)
       
  1010 fun DISCH tm thm = Thm.implies_intr (Dcterm.mk_prop tm) thm COMP impI
       
  1011   handle THM (msg, _, _) => raise RULES_ERR "DISCH" msg;
       
  1012 
       
  1013 fun DISCH_ALL thm = fold_rev DISCH (#hyps (Thm.crep_thm thm)) thm;
       
  1014 
       
  1015 
       
  1016 fun FILTER_DISCH_ALL P thm =
       
  1017  let fun check tm = P (Thm.term_of tm)
       
  1018  in  fold_rev (fn tm => fn th => if check tm then DISCH tm th else th) (chyps thm) thm
       
  1019  end;
       
  1020 
       
  1021 fun UNDISCH thm =
       
  1022    let val tm = Dcterm.mk_prop (#1 (Dcterm.dest_imp (cconcl thm)))
       
  1023    in Thm.implies_elim (thm RS mp) (ASSUME tm) end
       
  1024    handle Utils.ERR _ => raise RULES_ERR "UNDISCH" ""
       
  1025      | THM _ => raise RULES_ERR "UNDISCH" "";
       
  1026 
       
  1027 fun PROVE_HYP ath bth = MP (DISCH (cconcl ath) bth) ath;
       
  1028 
       
  1029 fun IMP_TRANS th1 th2 = th2 RS (th1 RS Thms.imp_trans)
       
  1030   handle THM (msg, _, _) => raise RULES_ERR "IMP_TRANS" msg;
       
  1031 
       
  1032 
       
  1033 (*----------------------------------------------------------------------------
       
  1034  *        Conjunction
       
  1035  *---------------------------------------------------------------------------*)
       
  1036 
       
  1037 fun CONJUNCT1 thm = thm RS conjunct1
       
  1038   handle THM (msg, _, _) => raise RULES_ERR "CONJUNCT1" msg;
       
  1039 
       
  1040 fun CONJUNCT2 thm = thm RS conjunct2
       
  1041   handle THM (msg, _, _) => raise RULES_ERR "CONJUNCT2" msg;
       
  1042 
       
  1043 fun CONJUNCTS th = CONJUNCTS (CONJUNCT1 th) @ CONJUNCTS (CONJUNCT2 th) handle Utils.ERR _ => [th];
       
  1044 
       
  1045 fun LIST_CONJ [] = raise RULES_ERR "LIST_CONJ" "empty list"
       
  1046   | LIST_CONJ [th] = th
       
  1047   | LIST_CONJ (th :: rst) = MP (MP (conjI COMP (impI RS impI)) th) (LIST_CONJ rst)
       
  1048       handle THM (msg, _, _) => raise RULES_ERR "LIST_CONJ" msg;
       
  1049 
       
  1050 
       
  1051 (*----------------------------------------------------------------------------
       
  1052  *        Disjunction
       
  1053  *---------------------------------------------------------------------------*)
       
  1054 local
       
  1055   val prop = Thm.prop_of disjI1
       
  1056   val [P,Q] = Misc_Legacy.term_vars prop
       
  1057   val disj1 = Thm.forall_intr (Thm.cterm_of @{context} Q) disjI1
       
  1058 in
       
  1059 fun DISJ1 thm tm = thm RS (Thm.forall_elim (Dcterm.drop_prop tm) disj1)
       
  1060   handle THM (msg, _, _) => raise RULES_ERR "DISJ1" msg;
       
  1061 end;
       
  1062 
       
  1063 local
       
  1064   val prop = Thm.prop_of disjI2
       
  1065   val [P,Q] = Misc_Legacy.term_vars prop
       
  1066   val disj2 = Thm.forall_intr (Thm.cterm_of @{context} P) disjI2
       
  1067 in
       
  1068 fun DISJ2 tm thm = thm RS (Thm.forall_elim (Dcterm.drop_prop tm) disj2)
       
  1069   handle THM (msg, _, _) => raise RULES_ERR "DISJ2" msg;
       
  1070 end;
       
  1071 
       
  1072 
       
  1073 (*----------------------------------------------------------------------------
       
  1074  *
       
  1075  *                   A1 |- M1, ..., An |- Mn
       
  1076  *     ---------------------------------------------------
       
  1077  *     [A1 |- M1 \/ ... \/ Mn, ..., An |- M1 \/ ... \/ Mn]
       
  1078  *
       
  1079  *---------------------------------------------------------------------------*)
       
  1080 
       
  1081 
       
  1082 fun EVEN_ORS thms =
       
  1083   let fun blue ldisjs [] _ = []
       
  1084         | blue ldisjs (th::rst) rdisjs =
       
  1085             let val tail = tl rdisjs
       
  1086                 val rdisj_tl = Dcterm.list_mk_disj tail
       
  1087             in fold_rev DISJ2 ldisjs (DISJ1 th rdisj_tl)
       
  1088                :: blue (ldisjs @ [cconcl th]) rst tail
       
  1089             end handle Utils.ERR _ => [fold_rev DISJ2 ldisjs th]
       
  1090    in blue [] thms (map cconcl thms) end;
       
  1091 
       
  1092 
       
  1093 (*----------------------------------------------------------------------------
       
  1094  *
       
  1095  *         A |- P \/ Q   B,P |- R    C,Q |- R
       
  1096  *     ---------------------------------------------------
       
  1097  *                     A U B U C |- R
       
  1098  *
       
  1099  *---------------------------------------------------------------------------*)
       
  1100 
       
  1101 fun DISJ_CASES th1 th2 th3 =
       
  1102   let
       
  1103     val c = Dcterm.drop_prop (cconcl th1);
       
  1104     val (disj1, disj2) = Dcterm.dest_disj c;
       
  1105     val th2' = DISCH disj1 th2;
       
  1106     val th3' = DISCH disj2 th3;
       
  1107   in
       
  1108     th3' RS (th2' RS (th1 RS Thms.tfl_disjE))
       
  1109       handle THM (msg, _, _) => raise RULES_ERR "DISJ_CASES" msg
       
  1110   end;
       
  1111 
       
  1112 
       
  1113 (*-----------------------------------------------------------------------------
       
  1114  *
       
  1115  *       |- A1 \/ ... \/ An     [A1 |- M, ..., An |- M]
       
  1116  *     ---------------------------------------------------
       
  1117  *                           |- M
       
  1118  *
       
  1119  * Note. The list of theorems may be all jumbled up, so we have to
       
  1120  * first organize it to align with the first argument (the disjunctive
       
  1121  * theorem).
       
  1122  *---------------------------------------------------------------------------*)
       
  1123 
       
  1124 fun organize eq =    (* a bit slow - analogous to insertion sort *)
       
  1125  let fun extract a alist =
       
  1126      let fun ex (_,[]) = raise RULES_ERR "organize" "not a permutation.1"
       
  1127            | ex(left,h::t) = if (eq h a) then (h,rev left@t) else ex(h::left,t)
       
  1128      in ex ([],alist)
       
  1129      end
       
  1130      fun place [] [] = []
       
  1131        | place (a::rst) alist =
       
  1132            let val (item,next) = extract a alist
       
  1133            in item::place rst next
       
  1134            end
       
  1135        | place _ _ = raise RULES_ERR "organize" "not a permutation.2"
       
  1136  in place
       
  1137  end;
       
  1138 
       
  1139 fun DISJ_CASESL disjth thl =
       
  1140    let val c = cconcl disjth
       
  1141        fun eq th atm =
       
  1142         exists (fn t => HOLogic.dest_Trueprop t aconv Thm.term_of atm) (Thm.hyps_of th)
       
  1143        val tml = Dcterm.strip_disj c
       
  1144        fun DL th [] = raise RULES_ERR "DISJ_CASESL" "no cases"
       
  1145          | DL th [th1] = PROVE_HYP th th1
       
  1146          | DL th [th1,th2] = DISJ_CASES th th1 th2
       
  1147          | DL th (th1::rst) =
       
  1148             let val tm = #2 (Dcterm.dest_disj (Dcterm.drop_prop(cconcl th)))
       
  1149              in DISJ_CASES th th1 (DL (ASSUME tm) rst) end
       
  1150    in DL disjth (organize eq tml thl)
       
  1151    end;
       
  1152 
       
  1153 
       
  1154 (*----------------------------------------------------------------------------
       
  1155  *        Universals
       
  1156  *---------------------------------------------------------------------------*)
       
  1157 local (* this is fragile *)
       
  1158   val prop = Thm.prop_of spec
       
  1159   val x = hd (tl (Misc_Legacy.term_vars prop))
       
  1160   val cTV = Thm.ctyp_of @{context} (type_of x)
       
  1161   val gspec = Thm.forall_intr (Thm.cterm_of @{context} x) spec
       
  1162 in
       
  1163 fun SPEC tm thm =
       
  1164    let val gspec' = Drule.instantiate_normalize ([(cTV, Thm.ctyp_of_cterm tm)], []) gspec
       
  1165    in thm RS (Thm.forall_elim tm gspec') end
       
  1166 end;
       
  1167 
       
  1168 fun SPEC_ALL thm = fold SPEC (#1 (Dcterm.strip_forall(cconcl thm))) thm;
       
  1169 
       
  1170 val ISPEC = SPEC
       
  1171 val ISPECL = fold ISPEC;
       
  1172 
       
  1173 (* Not optimized! Too complicated. *)
       
  1174 local
       
  1175   val prop = Thm.prop_of allI
       
  1176   val [P] = Misc_Legacy.add_term_vars (prop, [])
       
  1177   fun cty_theta ctxt = map (fn (i, (S, ty)) => apply2 (Thm.ctyp_of ctxt) (TVar (i, S), ty))
       
  1178   fun ctm_theta ctxt =
       
  1179     map (fn (i, (_, tm2)) =>
       
  1180       let val ctm2 = Thm.cterm_of ctxt tm2
       
  1181       in (Thm.cterm_of ctxt (Var (i, Thm.typ_of_cterm ctm2)), ctm2) end)
       
  1182   fun certify ctxt (ty_theta,tm_theta) =
       
  1183     (cty_theta ctxt (Vartab.dest ty_theta),
       
  1184      ctm_theta ctxt (Vartab.dest tm_theta))
       
  1185 in
       
  1186 fun GEN ctxt v th =
       
  1187    let val gth = Thm.forall_intr v th
       
  1188        val thy = Proof_Context.theory_of ctxt
       
  1189        val Const(@{const_name Pure.all},_)$Abs(x,ty,rst) = Thm.prop_of gth
       
  1190        val P' = Abs(x,ty, HOLogic.dest_Trueprop rst)  (* get rid of trueprop *)
       
  1191        val theta = Pattern.match thy (P,P') (Vartab.empty, Vartab.empty);
       
  1192        val allI2 = Drule.instantiate_normalize (certify ctxt theta) allI
       
  1193        val thm = Thm.implies_elim allI2 gth
       
  1194        val tp $ (A $ Abs(_,_,M)) = Thm.prop_of thm
       
  1195        val prop' = tp $ (A $ Abs(x,ty,M))
       
  1196    in ALPHA thm (Thm.cterm_of ctxt prop') end
       
  1197 end;
       
  1198 
       
  1199 fun GENL ctxt = fold_rev (GEN ctxt);
       
  1200 
       
  1201 fun GEN_ALL ctxt thm =
       
  1202   let
       
  1203     val prop = Thm.prop_of thm
       
  1204     val vlist = map (Thm.cterm_of ctxt) (Misc_Legacy.add_term_vars (prop, []))
       
  1205   in GENL ctxt vlist thm end;
       
  1206 
       
  1207 
       
  1208 fun MATCH_MP th1 th2 =
       
  1209    if (Dcterm.is_forall (Dcterm.drop_prop(cconcl th1)))
       
  1210    then MATCH_MP (th1 RS spec) th2
       
  1211    else MP th1 th2;
       
  1212 
       
  1213 
       
  1214 (*----------------------------------------------------------------------------
       
  1215  *        Existentials
       
  1216  *---------------------------------------------------------------------------*)
       
  1217 
       
  1218 
       
  1219 
       
  1220 (*---------------------------------------------------------------------------
       
  1221  * Existential elimination
       
  1222  *
       
  1223  *      A1 |- ?x.t[x]   ,   A2, "t[v]" |- t'
       
  1224  *      ------------------------------------     (variable v occurs nowhere)
       
  1225  *                A1 u A2 |- t'
       
  1226  *
       
  1227  *---------------------------------------------------------------------------*)
       
  1228 
       
  1229 fun CHOOSE ctxt (fvar, exth) fact =
       
  1230   let
       
  1231     val lam = #2 (Dcterm.dest_comb (Dcterm.drop_prop (cconcl exth)))
       
  1232     val redex = Dcterm.capply lam fvar
       
  1233     val t$u = Thm.term_of redex
       
  1234     val residue = Thm.cterm_of ctxt (Term.betapply (t, u))
       
  1235   in
       
  1236     GEN ctxt fvar (DISCH residue fact) RS (exth RS Thms.choose_thm)
       
  1237       handle THM (msg, _, _) => raise RULES_ERR "CHOOSE" msg
       
  1238   end;
       
  1239 
       
  1240 local
       
  1241   val prop = Thm.prop_of exI
       
  1242   val [P, x] = map (Thm.cterm_of @{context}) (Misc_Legacy.term_vars prop)
       
  1243 in
       
  1244 fun EXISTS (template,witness) thm =
       
  1245   let val abstr = #2 (Dcterm.dest_comb template) in
       
  1246     thm RS (cterm_instantiate [(P, abstr), (x, witness)] exI)
       
  1247       handle THM (msg, _, _) => raise RULES_ERR "EXISTS" msg
       
  1248   end
       
  1249 end;
       
  1250 
       
  1251 (*----------------------------------------------------------------------------
       
  1252  *
       
  1253  *         A |- M
       
  1254  *   -------------------   [v_1,...,v_n]
       
  1255  *    A |- ?v1...v_n. M
       
  1256  *
       
  1257  *---------------------------------------------------------------------------*)
       
  1258 
       
  1259 fun EXISTL vlist th =
       
  1260   fold_rev (fn v => fn thm => EXISTS(Dcterm.mk_exists(v,cconcl thm), v) thm)
       
  1261            vlist th;
       
  1262 
       
  1263 
       
  1264 (*----------------------------------------------------------------------------
       
  1265  *
       
  1266  *       A |- M[x_1,...,x_n]
       
  1267  *   ----------------------------   [(x |-> y)_1,...,(x |-> y)_n]
       
  1268  *       A |- ?y_1...y_n. M
       
  1269  *
       
  1270  *---------------------------------------------------------------------------*)
       
  1271 (* Could be improved, but needs "subst_free" for certified terms *)
       
  1272 
       
  1273 fun IT_EXISTS ctxt blist th =
       
  1274   let
       
  1275     val blist' = map (apply2 Thm.term_of) blist
       
  1276     fun ex v M = Thm.cterm_of ctxt (USyntax.mk_exists{Bvar=v,Body = M})
       
  1277   in
       
  1278     fold_rev (fn (b as (r1,r2)) => fn thm =>
       
  1279         EXISTS(ex r2 (subst_free [b]
       
  1280                    (HOLogic.dest_Trueprop(Thm.prop_of thm))), Thm.cterm_of ctxt r1)
       
  1281               thm)
       
  1282        blist' th
       
  1283   end;
       
  1284 
       
  1285 (*---------------------------------------------------------------------------
       
  1286  *  Faster version, that fails for some as yet unknown reason
       
  1287  * fun IT_EXISTS blist th =
       
  1288  *    let val {thy,...} = rep_thm th
       
  1289  *        val tych = cterm_of thy
       
  1290  *        fun detype (x,y) = ((#t o rep_cterm) x, (#t o rep_cterm) y)
       
  1291  *   in
       
  1292  *  fold (fn (b as (r1,r2), thm) =>
       
  1293  *  EXISTS(D.mk_exists(r2, tych(subst_free[detype b](#t(rep_cterm(cconcl thm))))),
       
  1294  *           r1) thm)  blist th
       
  1295  *   end;
       
  1296  *---------------------------------------------------------------------------*)
       
  1297 
       
  1298 (*----------------------------------------------------------------------------
       
  1299  *        Rewriting
       
  1300  *---------------------------------------------------------------------------*)
       
  1301 
       
  1302 fun SUBS ctxt thl =
       
  1303   rewrite_rule ctxt (map (fn th => th RS eq_reflection handle THM _ => th) thl);
       
  1304 
       
  1305 val rew_conv = Raw_Simplifier.rewrite_cterm (true, false, false) (K (K NONE));
       
  1306 
       
  1307 fun simpl_conv ctxt thl ctm =
       
  1308  rew_conv (ctxt addsimps thl) ctm RS meta_eq_to_obj_eq;
       
  1309 
       
  1310 
       
  1311 fun RIGHT_ASSOC ctxt = rewrite_rule ctxt [Thms.disj_assoc];
       
  1312 
       
  1313 
       
  1314 
       
  1315 (*---------------------------------------------------------------------------
       
  1316  *                  TERMINATION CONDITION EXTRACTION
       
  1317  *---------------------------------------------------------------------------*)
       
  1318 
       
  1319 
       
  1320 (* Object language quantifier, i.e., "!" *)
       
  1321 fun Forall v M = USyntax.mk_forall{Bvar=v, Body=M};
       
  1322 
       
  1323 
       
  1324 (* Fragile: it's a cong if it is not "R y x ==> cut f R x y = f y" *)
       
  1325 fun is_cong thm =
       
  1326   case (Thm.prop_of thm) of
       
  1327     (Const(@{const_name Pure.imp},_)$(Const(@{const_name Trueprop},_)$ _) $
       
  1328       (Const(@{const_name Pure.eq},_) $ (Const (@{const_name Wfrec.cut},_) $ f $ R $ a $ x) $ _)) =>
       
  1329         false
       
  1330   | _ => true;
       
  1331 
       
  1332 
       
  1333 fun dest_equal(Const (@{const_name Pure.eq},_) $
       
  1334                (Const (@{const_name Trueprop},_) $ lhs)
       
  1335                $ (Const (@{const_name Trueprop},_) $ rhs)) = {lhs=lhs, rhs=rhs}
       
  1336   | dest_equal(Const (@{const_name Pure.eq},_) $ lhs $ rhs) = {lhs=lhs, rhs=rhs}
       
  1337   | dest_equal tm = USyntax.dest_eq tm;
       
  1338 
       
  1339 fun get_lhs tm = #lhs(dest_equal (HOLogic.dest_Trueprop tm));
       
  1340 
       
  1341 fun dest_all used (Const(@{const_name Pure.all},_) $ (a as Abs _)) = USyntax.dest_abs used a
       
  1342   | dest_all _ _ = raise RULES_ERR "dest_all" "not a !!";
       
  1343 
       
  1344 val is_all = can (dest_all []);
       
  1345 
       
  1346 fun strip_all used fm =
       
  1347    if (is_all fm)
       
  1348    then let val ({Bvar, Body}, used') = dest_all used fm
       
  1349             val (bvs, core, used'') = strip_all used' Body
       
  1350         in ((Bvar::bvs), core, used'')
       
  1351         end
       
  1352    else ([], fm, used);
       
  1353 
       
  1354 fun break_all(Const(@{const_name Pure.all},_) $ Abs (_,_,body)) = body
       
  1355   | break_all _ = raise RULES_ERR "break_all" "not a !!";
       
  1356 
       
  1357 fun list_break_all(Const(@{const_name Pure.all},_) $ Abs (s,ty,body)) =
       
  1358      let val (L,core) = list_break_all body
       
  1359      in ((s,ty)::L, core)
       
  1360      end
       
  1361   | list_break_all tm = ([],tm);
       
  1362 
       
  1363 (*---------------------------------------------------------------------------
       
  1364  * Rename a term of the form
       
  1365  *
       
  1366  *      !!x1 ...xn. x1=M1 ==> ... ==> xn=Mn
       
  1367  *                  ==> ((%v1...vn. Q) x1 ... xn = g x1 ... xn.
       
  1368  * to one of
       
  1369  *
       
  1370  *      !!v1 ... vn. v1=M1 ==> ... ==> vn=Mn
       
  1371  *      ==> ((%v1...vn. Q) v1 ... vn = g v1 ... vn.
       
  1372  *
       
  1373  * This prevents name problems in extraction, and helps the result to read
       
  1374  * better. There is a problem with varstructs, since they can introduce more
       
  1375  * than n variables, and some extra reasoning needs to be done.
       
  1376  *---------------------------------------------------------------------------*)
       
  1377 
       
  1378 fun get ([],_,L) = rev L
       
  1379   | get (ant::rst,n,L) =
       
  1380       case (list_break_all ant)
       
  1381         of ([],_) => get (rst, n+1,L)
       
  1382          | (vlist,body) =>
       
  1383             let val eq = Logic.strip_imp_concl body
       
  1384                 val (f,args) = USyntax.strip_comb (get_lhs eq)
       
  1385                 val (vstrl,_) = USyntax.strip_abs f
       
  1386                 val names  =
       
  1387                   Name.variant_list (Misc_Legacy.add_term_names(body, [])) (map (#1 o dest_Free) vstrl)
       
  1388             in get (rst, n+1, (names,n)::L) end
       
  1389             handle TERM _ => get (rst, n+1, L)
       
  1390               | Utils.ERR _ => get (rst, n+1, L);
       
  1391 
       
  1392 (* Note: Thm.rename_params_rule counts from 1, not 0 *)
       
  1393 fun rename thm =
       
  1394   let
       
  1395     val ants = Logic.strip_imp_prems (Thm.prop_of thm)
       
  1396     val news = get (ants,1,[])
       
  1397   in fold Thm.rename_params_rule news thm end;
       
  1398 
       
  1399 
       
  1400 (*---------------------------------------------------------------------------
       
  1401  * Beta-conversion to the rhs of an equation (taken from hol90/drule.sml)
       
  1402  *---------------------------------------------------------------------------*)
       
  1403 
       
  1404 fun list_beta_conv tm =
       
  1405   let fun rbeta th = Thm.transitive th (Thm.beta_conversion false (#2(Dcterm.dest_eq(cconcl th))))
       
  1406       fun iter [] = Thm.reflexive tm
       
  1407         | iter (v::rst) = rbeta (Thm.combination(iter rst) (Thm.reflexive v))
       
  1408   in iter  end;
       
  1409 
       
  1410 
       
  1411 (*---------------------------------------------------------------------------
       
  1412  * Trace information for the rewriter
       
  1413  *---------------------------------------------------------------------------*)
       
  1414 val tracing = Unsynchronized.ref false;
       
  1415 
       
  1416 fun say s = if !tracing then writeln s else ();
       
  1417 
       
  1418 fun print_thms ctxt s L =
       
  1419   say (cat_lines (s :: map (Display.string_of_thm ctxt) L));
       
  1420 
       
  1421 fun print_term ctxt s t =
       
  1422   say (cat_lines [s, Syntax.string_of_term ctxt t]);
       
  1423 
       
  1424 
       
  1425 (*---------------------------------------------------------------------------
       
  1426  * General abstraction handlers, should probably go in USyntax.
       
  1427  *---------------------------------------------------------------------------*)
       
  1428 fun mk_aabs (vstr, body) =
       
  1429   USyntax.mk_abs {Bvar = vstr, Body = body}
       
  1430   handle Utils.ERR _ => USyntax.mk_pabs {varstruct = vstr, body = body};
       
  1431 
       
  1432 fun list_mk_aabs (vstrl,tm) =
       
  1433     fold_rev (fn vstr => fn tm => mk_aabs(vstr,tm)) vstrl tm;
       
  1434 
       
  1435 fun dest_aabs used tm =
       
  1436    let val ({Bvar,Body}, used') = USyntax.dest_abs used tm
       
  1437    in (Bvar, Body, used') end
       
  1438    handle Utils.ERR _ =>
       
  1439      let val {varstruct, body, used} = USyntax.dest_pabs used tm
       
  1440      in (varstruct, body, used) end;
       
  1441 
       
  1442 fun strip_aabs used tm =
       
  1443    let val (vstr, body, used') = dest_aabs used tm
       
  1444        val (bvs, core, used'') = strip_aabs used' body
       
  1445    in (vstr::bvs, core, used'') end
       
  1446    handle Utils.ERR _ => ([], tm, used);
       
  1447 
       
  1448 fun dest_combn tm 0 = (tm,[])
       
  1449   | dest_combn tm n =
       
  1450      let val {Rator,Rand} = USyntax.dest_comb tm
       
  1451          val (f,rands) = dest_combn Rator (n-1)
       
  1452      in (f,Rand::rands)
       
  1453      end;
       
  1454 
       
  1455 
       
  1456 
       
  1457 
       
  1458 local fun dest_pair M = let val {fst,snd} = USyntax.dest_pair M in (fst,snd) end
       
  1459       fun mk_fst tm =
       
  1460           let val ty as Type(@{type_name Product_Type.prod}, [fty,sty]) = type_of tm
       
  1461           in  Const (@{const_name Product_Type.fst}, ty --> fty) $ tm  end
       
  1462       fun mk_snd tm =
       
  1463           let val ty as Type(@{type_name Product_Type.prod}, [fty,sty]) = type_of tm
       
  1464           in  Const (@{const_name Product_Type.snd}, ty --> sty) $ tm  end
       
  1465 in
       
  1466 fun XFILL tych x vstruct =
       
  1467   let fun traverse p xocc L =
       
  1468         if (is_Free p)
       
  1469         then tych xocc::L
       
  1470         else let val (p1,p2) = dest_pair p
       
  1471              in traverse p1 (mk_fst xocc) (traverse p2  (mk_snd xocc) L)
       
  1472              end
       
  1473   in
       
  1474   traverse vstruct x []
       
  1475 end end;
       
  1476 
       
  1477 (*---------------------------------------------------------------------------
       
  1478  * Replace a free tuple (vstr) by a universally quantified variable (a).
       
  1479  * Note that the notion of "freeness" for a tuple is different than for a
       
  1480  * variable: if variables in the tuple also occur in any other place than
       
  1481  * an occurrences of the tuple, they aren't "free" (which is thus probably
       
  1482  *  the wrong word to use).
       
  1483  *---------------------------------------------------------------------------*)
       
  1484 
       
  1485 fun VSTRUCT_ELIM ctxt tych a vstr th =
       
  1486   let val L = USyntax.free_vars_lr vstr
       
  1487       val bind1 = tych (HOLogic.mk_Trueprop (HOLogic.mk_eq(a,vstr)))
       
  1488       val thm1 = Thm.implies_intr bind1 (SUBS ctxt [SYM(Thm.assume bind1)] th)
       
  1489       val thm2 = forall_intr_list (map tych L) thm1
       
  1490       val thm3 = forall_elim_list (XFILL tych a vstr) thm2
       
  1491   in refl RS
       
  1492      rewrite_rule ctxt [Thm.symmetric (@{thm surjective_pairing} RS eq_reflection)] thm3
       
  1493   end;
       
  1494 
       
  1495 fun PGEN ctxt tych a vstr th =
       
  1496   let val a1 = tych a
       
  1497       val vstr1 = tych vstr
       
  1498   in
       
  1499   Thm.forall_intr a1
       
  1500      (if (is_Free vstr)
       
  1501       then cterm_instantiate [(vstr1,a1)] th
       
  1502       else VSTRUCT_ELIM ctxt tych a vstr th)
       
  1503   end;
       
  1504 
       
  1505 
       
  1506 (*---------------------------------------------------------------------------
       
  1507  * Takes apart a paired beta-redex, looking like "(\(x,y).N) vstr", into
       
  1508  *
       
  1509  *     (([x,y],N),vstr)
       
  1510  *---------------------------------------------------------------------------*)
       
  1511 fun dest_pbeta_redex used M n =
       
  1512   let val (f,args) = dest_combn M n
       
  1513       val dummy = dest_aabs used f
       
  1514   in (strip_aabs used f,args)
       
  1515   end;
       
  1516 
       
  1517 fun pbeta_redex M n = can (fn t => dest_pbeta_redex [] t n) M;
       
  1518 
       
  1519 fun dest_impl tm =
       
  1520   let val ants = Logic.strip_imp_prems tm
       
  1521       val eq = Logic.strip_imp_concl tm
       
  1522   in (ants,get_lhs eq)
       
  1523   end;
       
  1524 
       
  1525 fun restricted t = is_some (USyntax.find_term
       
  1526                             (fn (Const(@{const_name Wfrec.cut},_)) =>true | _ => false)
       
  1527                             t)
       
  1528 
       
  1529 fun CONTEXT_REWRITE_RULE main_ctxt (func, G, cut_lemma, congs) th =
       
  1530  let val globals = func::G
       
  1531      val ctxt0 = empty_simpset main_ctxt
       
  1532      val pbeta_reduce = simpl_conv ctxt0 [@{thm split_conv} RS eq_reflection];
       
  1533      val tc_list = Unsynchronized.ref []: term list Unsynchronized.ref
       
  1534      val cut_lemma' = cut_lemma RS eq_reflection
       
  1535      fun prover used ctxt thm =
       
  1536      let fun cong_prover ctxt thm =
       
  1537          let val dummy = say "cong_prover:"
       
  1538              val cntxt = Simplifier.prems_of ctxt
       
  1539              val dummy = print_thms ctxt "cntxt:" cntxt
       
  1540              val dummy = say "cong rule:"
       
  1541              val dummy = say (Display.string_of_thm ctxt thm)
       
  1542              (* Unquantified eliminate *)
       
  1543              fun uq_eliminate (thm,imp) =
       
  1544                  let val tych = Thm.cterm_of ctxt
       
  1545                      val _ = print_term ctxt "To eliminate:" imp
       
  1546                      val ants = map tych (Logic.strip_imp_prems imp)
       
  1547                      val eq = Logic.strip_imp_concl imp
       
  1548                      val lhs = tych(get_lhs eq)
       
  1549                      val ctxt' = Simplifier.add_prems (map ASSUME ants) ctxt
       
  1550                      val lhs_eq_lhs1 = Raw_Simplifier.rewrite_cterm (false,true,false) (prover used) ctxt' lhs
       
  1551                        handle Utils.ERR _ => Thm.reflexive lhs
       
  1552                      val _ = print_thms ctxt' "proven:" [lhs_eq_lhs1]
       
  1553                      val lhs_eq_lhs2 = implies_intr_list ants lhs_eq_lhs1
       
  1554                      val lhs_eeq_lhs2 = lhs_eq_lhs2 RS meta_eq_to_obj_eq
       
  1555                   in
       
  1556                   lhs_eeq_lhs2 COMP thm
       
  1557                   end
       
  1558              fun pq_eliminate (thm, vlist, imp_body, lhs_eq) =
       
  1559               let val ((vstrl, _, used'), args) = dest_pbeta_redex used lhs_eq (length vlist)
       
  1560                   val dummy = forall (op aconv) (ListPair.zip (vlist, args))
       
  1561                     orelse error "assertion failed in CONTEXT_REWRITE_RULE"
       
  1562                   val imp_body1 = subst_free (ListPair.zip (args, vstrl))
       
  1563                                              imp_body
       
  1564                   val tych = Thm.cterm_of ctxt
       
  1565                   val ants1 = map tych (Logic.strip_imp_prems imp_body1)
       
  1566                   val eq1 = Logic.strip_imp_concl imp_body1
       
  1567                   val Q = get_lhs eq1
       
  1568                   val QeqQ1 = pbeta_reduce (tych Q)
       
  1569                   val Q1 = #2(Dcterm.dest_eq(cconcl QeqQ1))
       
  1570                   val ctxt' = Simplifier.add_prems (map ASSUME ants1) ctxt
       
  1571                   val Q1eeqQ2 = Raw_Simplifier.rewrite_cterm (false,true,false) (prover used') ctxt' Q1
       
  1572                                 handle Utils.ERR _ => Thm.reflexive Q1
       
  1573                   val Q2 = #2 (Logic.dest_equals (Thm.prop_of Q1eeqQ2))
       
  1574                   val Q3 = tych(list_comb(list_mk_aabs(vstrl,Q2),vstrl))
       
  1575                   val Q2eeqQ3 = Thm.symmetric(pbeta_reduce Q3 RS eq_reflection)
       
  1576                   val thA = Thm.transitive(QeqQ1 RS eq_reflection) Q1eeqQ2
       
  1577                   val QeeqQ3 = Thm.transitive thA Q2eeqQ3 handle THM _ =>
       
  1578                                ((Q2eeqQ3 RS meta_eq_to_obj_eq)
       
  1579                                 RS ((thA RS meta_eq_to_obj_eq) RS trans))
       
  1580                                 RS eq_reflection
       
  1581                   val impth = implies_intr_list ants1 QeeqQ3
       
  1582                   val impth1 = impth RS meta_eq_to_obj_eq
       
  1583                   (* Need to abstract *)
       
  1584                   val ant_th = Utils.itlist2 (PGEN ctxt' tych) args vstrl impth1
       
  1585               in ant_th COMP thm
       
  1586               end
       
  1587              fun q_eliminate (thm, imp) =
       
  1588               let val (vlist, imp_body, used') = strip_all used imp
       
  1589                   val (ants,Q) = dest_impl imp_body
       
  1590               in if (pbeta_redex Q) (length vlist)
       
  1591                  then pq_eliminate (thm, vlist, imp_body, Q)
       
  1592                  else
       
  1593                  let val tych = Thm.cterm_of ctxt
       
  1594                      val ants1 = map tych ants
       
  1595                      val ctxt' = Simplifier.add_prems (map ASSUME ants1) ctxt
       
  1596                      val Q_eeq_Q1 = Raw_Simplifier.rewrite_cterm
       
  1597                         (false,true,false) (prover used') ctxt' (tych Q)
       
  1598                       handle Utils.ERR _ => Thm.reflexive (tych Q)
       
  1599                      val lhs_eeq_lhs2 = implies_intr_list ants1 Q_eeq_Q1
       
  1600                      val lhs_eq_lhs2 = lhs_eeq_lhs2 RS meta_eq_to_obj_eq
       
  1601                      val ant_th = forall_intr_list(map tych vlist)lhs_eq_lhs2
       
  1602                  in
       
  1603                  ant_th COMP thm
       
  1604               end end
       
  1605 
       
  1606              fun eliminate thm =
       
  1607                case Thm.prop_of thm of
       
  1608                  Const(@{const_name Pure.imp},_) $ imp $ _ =>
       
  1609                    eliminate
       
  1610                     (if not(is_all imp)
       
  1611                      then uq_eliminate (thm, imp)
       
  1612                      else q_eliminate (thm, imp))
       
  1613                             (* Assume that the leading constant is ==,   *)
       
  1614                 | _ => thm  (* if it is not a ==>                        *)
       
  1615          in SOME(eliminate (rename thm)) end
       
  1616          handle Utils.ERR _ => NONE    (* FIXME handle THM as well?? *)
       
  1617 
       
  1618         fun restrict_prover ctxt thm =
       
  1619           let val _ = say "restrict_prover:"
       
  1620               val cntxt = rev (Simplifier.prems_of ctxt)
       
  1621               val _ = print_thms ctxt "cntxt:" cntxt
       
  1622               val Const(@{const_name Pure.imp},_) $ (Const(@{const_name Trueprop},_) $ A) $ _ =
       
  1623                 Thm.prop_of thm
       
  1624               fun genl tm = let val vlist = subtract (op aconv) globals
       
  1625                                            (Misc_Legacy.add_term_frees(tm,[]))
       
  1626                             in fold_rev Forall vlist tm
       
  1627                             end
       
  1628               (*--------------------------------------------------------------
       
  1629                * This actually isn't quite right, since it will think that
       
  1630                * not-fully applied occs. of "f" in the context mean that the
       
  1631                * current call is nested. The real solution is to pass in a
       
  1632                * term "f v1..vn" which is a pattern that any full application
       
  1633                * of "f" will match.
       
  1634                *-------------------------------------------------------------*)
       
  1635               val func_name = #1(dest_Const func)
       
  1636               fun is_func (Const (name,_)) = (name = func_name)
       
  1637                 | is_func _                = false
       
  1638               val rcontext = rev cntxt
       
  1639               val cncl = HOLogic.dest_Trueprop o Thm.prop_of
       
  1640               val antl = case rcontext of [] => []
       
  1641                          | _   => [USyntax.list_mk_conj(map cncl rcontext)]
       
  1642               val TC = genl(USyntax.list_mk_imp(antl, A))
       
  1643               val _ = print_term ctxt "func:" func
       
  1644               val _ = print_term ctxt "TC:" (HOLogic.mk_Trueprop TC)
       
  1645               val _ = tc_list := (TC :: !tc_list)
       
  1646               val nestedp = is_some (USyntax.find_term is_func TC)
       
  1647               val _ = if nestedp then say "nested" else say "not_nested"
       
  1648               val th' = if nestedp then raise RULES_ERR "solver" "nested function"
       
  1649                         else let val cTC = Thm.cterm_of ctxt (HOLogic.mk_Trueprop TC)
       
  1650                              in case rcontext of
       
  1651                                 [] => SPEC_ALL(ASSUME cTC)
       
  1652                                | _ => MP (SPEC_ALL (ASSUME cTC))
       
  1653                                          (LIST_CONJ rcontext)
       
  1654                              end
       
  1655               val th'' = th' RS thm
       
  1656           in SOME (th'')
       
  1657           end handle Utils.ERR _ => NONE    (* FIXME handle THM as well?? *)
       
  1658     in
       
  1659     (if (is_cong thm) then cong_prover else restrict_prover) ctxt thm
       
  1660     end
       
  1661     val ctm = Thm.cprop_of th
       
  1662     val names = Misc_Legacy.add_term_names (Thm.term_of ctm, [])
       
  1663     val th1 =
       
  1664       Raw_Simplifier.rewrite_cterm (false, true, false)
       
  1665         (prover names) (ctxt0 addsimps [cut_lemma'] |> fold Simplifier.add_eqcong congs) ctm
       
  1666     val th2 = Thm.equal_elim th1 th
       
  1667  in
       
  1668  (th2, filter_out restricted (!tc_list))
       
  1669  end;
       
  1670 
       
  1671 
       
  1672 fun prove ctxt strict (t, tac) =
       
  1673   let
       
  1674     val ctxt' = Variable.auto_fixes t ctxt;
       
  1675   in
       
  1676     if strict
       
  1677     then Goal.prove ctxt' [] [] t (K tac)
       
  1678     else Goal.prove ctxt' [] [] t (K tac)
       
  1679       handle ERROR msg => (warning msg; raise RULES_ERR "prove" msg)
       
  1680   end;
       
  1681 
       
  1682 end;
       
  1683 
       
  1684 
       
  1685 (*** theory operations ***)
       
  1686 
       
  1687 structure Thry: THRY =
       
  1688 struct
       
  1689 
       
  1690 
       
  1691 fun THRY_ERR func mesg = Utils.ERR {module = "Thry", func = func, mesg = mesg};
       
  1692 
       
  1693 
       
  1694 (*---------------------------------------------------------------------------
       
  1695  *    Matching
       
  1696  *---------------------------------------------------------------------------*)
       
  1697 
       
  1698 local
       
  1699 
       
  1700 fun tybind (ixn, (S, T)) = (TVar (ixn, S), T);
       
  1701 
       
  1702 in
       
  1703 
       
  1704 fun match_term thry pat ob =
       
  1705   let
       
  1706     val (ty_theta, tm_theta) = Pattern.match thry (pat,ob) (Vartab.empty, Vartab.empty);
       
  1707     fun tmbind (ixn, (T, t)) = (Var (ixn, Envir.subst_type ty_theta T), t)
       
  1708   in (map tmbind (Vartab.dest tm_theta), map tybind (Vartab.dest ty_theta))
       
  1709   end;
       
  1710 
       
  1711 fun match_type thry pat ob =
       
  1712   map tybind (Vartab.dest (Sign.typ_match thry (pat, ob) Vartab.empty));
       
  1713 
       
  1714 end;
       
  1715 
       
  1716 
       
  1717 (*---------------------------------------------------------------------------
       
  1718  * Typing
       
  1719  *---------------------------------------------------------------------------*)
       
  1720 
       
  1721 fun typecheck thy t =
       
  1722   Thm.global_cterm_of thy t
       
  1723     handle TYPE (msg, _, _) => raise THRY_ERR "typecheck" msg
       
  1724       | TERM (msg, _) => raise THRY_ERR "typecheck" msg;
       
  1725 
       
  1726 
       
  1727 (*---------------------------------------------------------------------------
       
  1728  * Get information about datatypes
       
  1729  *---------------------------------------------------------------------------*)
       
  1730 
       
  1731 fun match_info thy dtco =
       
  1732   case (BNF_LFP_Compat.get_info thy [BNF_LFP_Compat.Keep_Nesting] dtco,
       
  1733          BNF_LFP_Compat.get_constrs thy dtco) of
       
  1734       (SOME {case_name, ... }, SOME constructors) =>
       
  1735         SOME {case_const = Const (case_name, Sign.the_const_type thy case_name), constructors = map Const constructors}
       
  1736     | _ => NONE;
       
  1737 
       
  1738 fun induct_info thy dtco = case BNF_LFP_Compat.get_info thy [BNF_LFP_Compat.Keep_Nesting] dtco of
       
  1739         NONE => NONE
       
  1740       | SOME {nchotomy, ...} =>
       
  1741           SOME {nchotomy = nchotomy,
       
  1742                 constructors = (map Const o the o BNF_LFP_Compat.get_constrs thy) dtco};
       
  1743 
       
  1744 fun extract_info thy =
       
  1745  let val infos = map snd (Symtab.dest (BNF_LFP_Compat.get_all thy [BNF_LFP_Compat.Keep_Nesting]))
       
  1746  in {case_congs = map (mk_meta_eq o #case_cong) infos,
       
  1747      case_rewrites = maps (map mk_meta_eq o #case_rewrites) infos}
       
  1748  end;
       
  1749 
       
  1750 
       
  1751 end;
       
  1752 
       
  1753 
       
  1754 (*** first part of main module ***)
       
  1755 
       
  1756 structure Prim: PRIM =
       
  1757 struct
       
  1758 
       
  1759 val trace = Unsynchronized.ref false;
       
  1760 
       
  1761 
       
  1762 fun TFL_ERR func mesg = Utils.ERR {module = "Tfl", func = func, mesg = mesg};
       
  1763 
       
  1764 val concl = #2 o Rules.dest_thm;
       
  1765 val hyp = #1 o Rules.dest_thm;
       
  1766 
       
  1767 val list_mk_type = Utils.end_itlist (curry (op -->));
       
  1768 
       
  1769 fun front_last [] = raise TFL_ERR "front_last" "empty list"
       
  1770   | front_last [x] = ([],x)
       
  1771   | front_last (h::t) =
       
  1772      let val (pref,x) = front_last t
       
  1773      in
       
  1774         (h::pref,x)
       
  1775      end;
       
  1776 
       
  1777 
       
  1778 (*---------------------------------------------------------------------------
       
  1779  * The next function is common to pattern-match translation and
       
  1780  * proof of completeness of cases for the induction theorem.
       
  1781  *
       
  1782  * The curried function "gvvariant" returns a function to generate distinct
       
  1783  * variables that are guaranteed not to be in names.  The names of
       
  1784  * the variables go u, v, ..., z, aa, ..., az, ...  The returned
       
  1785  * function contains embedded refs!
       
  1786  *---------------------------------------------------------------------------*)
       
  1787 fun gvvariant names =
       
  1788   let val slist = Unsynchronized.ref names
       
  1789       val vname = Unsynchronized.ref "u"
       
  1790       fun new() =
       
  1791          if member (op =) (!slist) (!vname)
       
  1792          then (vname := Symbol.bump_string (!vname);  new())
       
  1793          else (slist := !vname :: !slist;  !vname)
       
  1794   in
       
  1795   fn ty => Free(new(), ty)
       
  1796   end;
       
  1797 
       
  1798 
       
  1799 (*---------------------------------------------------------------------------
       
  1800  * Used in induction theorem production. This is the simple case of
       
  1801  * partitioning up pattern rows by the leading constructor.
       
  1802  *---------------------------------------------------------------------------*)
       
  1803 fun ipartition gv (constructors,rows) =
       
  1804   let fun pfail s = raise TFL_ERR "partition.part" s
       
  1805       fun part {constrs = [],   rows = [],   A} = rev A
       
  1806         | part {constrs = [],   rows = _::_, A} = pfail"extra cases in defn"
       
  1807         | part {constrs = _::_, rows = [],   A} = pfail"cases missing in defn"
       
  1808         | part {constrs = c::crst, rows,     A} =
       
  1809           let val (c, T) = dest_Const c
       
  1810               val L = binder_types T
       
  1811               val (in_group, not_in_group) =
       
  1812                fold_rev (fn (row as (p::rst, rhs)) =>
       
  1813                          fn (in_group,not_in_group) =>
       
  1814                   let val (pc,args) = USyntax.strip_comb p
       
  1815                   in if (#1(dest_Const pc) = c)
       
  1816                      then ((args@rst, rhs)::in_group, not_in_group)
       
  1817                      else (in_group, row::not_in_group)
       
  1818                   end)      rows ([],[])
       
  1819               val col_types = Utils.take type_of (length L, #1(hd in_group))
       
  1820           in
       
  1821           part{constrs = crst, rows = not_in_group,
       
  1822                A = {constructor = c,
       
  1823                     new_formals = map gv col_types,
       
  1824                     group = in_group}::A}
       
  1825           end
       
  1826   in part{constrs = constructors, rows = rows, A = []}
       
  1827   end;
       
  1828 
       
  1829 
       
  1830 
       
  1831 (*---------------------------------------------------------------------------
       
  1832  * Each pattern carries with it a tag (i,b) where
       
  1833  * i is the clause it came from and
       
  1834  * b=true indicates that clause was given by the user
       
  1835  * (or is an instantiation of a user supplied pattern)
       
  1836  * b=false --> i = ~1
       
  1837  *---------------------------------------------------------------------------*)
       
  1838 
       
  1839 type pattern = term * (int * bool)
       
  1840 
       
  1841 fun pattern_map f (tm,x) = (f tm, x);
       
  1842 
       
  1843 fun pattern_subst theta = pattern_map (subst_free theta);
       
  1844 
       
  1845 val pat_of = fst;
       
  1846 fun row_of_pat x = fst (snd x);
       
  1847 fun given x = snd (snd x);
       
  1848 
       
  1849 (*---------------------------------------------------------------------------
       
  1850  * Produce an instance of a constructor, plus genvars for its arguments.
       
  1851  *---------------------------------------------------------------------------*)
       
  1852 fun fresh_constr ty_match colty gv c =
       
  1853   let val (_,Ty) = dest_Const c
       
  1854       val L = binder_types Ty
       
  1855       and ty = body_type Ty
       
  1856       val ty_theta = ty_match ty colty
       
  1857       val c' = USyntax.inst ty_theta c
       
  1858       val gvars = map (USyntax.inst ty_theta o gv) L
       
  1859   in (c', gvars)
       
  1860   end;
       
  1861 
       
  1862 
       
  1863 (*---------------------------------------------------------------------------
       
  1864  * Goes through a list of rows and picks out the ones beginning with a
       
  1865  * pattern with constructor = name.
       
  1866  *---------------------------------------------------------------------------*)
       
  1867 fun mk_group name rows =
       
  1868   fold_rev (fn (row as ((prfx, p::rst), rhs)) =>
       
  1869             fn (in_group,not_in_group) =>
       
  1870                let val (pc,args) = USyntax.strip_comb p
       
  1871                in if ((#1 (Term.dest_Const pc) = name) handle TERM _ => false)
       
  1872                   then (((prfx,args@rst), rhs)::in_group, not_in_group)
       
  1873                   else (in_group, row::not_in_group) end)
       
  1874       rows ([],[]);
       
  1875 
       
  1876 (*---------------------------------------------------------------------------
       
  1877  * Partition the rows. Not efficient: we should use hashing.
       
  1878  *---------------------------------------------------------------------------*)
       
  1879 fun partition _ _ (_,_,_,[]) = raise TFL_ERR "partition" "no rows"
       
  1880   | partition gv ty_match
       
  1881               (constructors, colty, res_ty, rows as (((prfx,_),_)::_)) =
       
  1882 let val fresh = fresh_constr ty_match colty gv
       
  1883      fun part {constrs = [],      rows, A} = rev A
       
  1884        | part {constrs = c::crst, rows, A} =
       
  1885          let val (c',gvars) = fresh c
       
  1886              val (in_group, not_in_group) = mk_group (#1 (dest_Const c')) rows
       
  1887              val in_group' =
       
  1888                  if (null in_group)  (* Constructor not given *)
       
  1889                  then [((prfx, #2(fresh c)), (USyntax.ARB res_ty, (~1,false)))]
       
  1890                  else in_group
       
  1891          in
       
  1892          part{constrs = crst,
       
  1893               rows = not_in_group,
       
  1894               A = {constructor = c',
       
  1895                    new_formals = gvars,
       
  1896                    group = in_group'}::A}
       
  1897          end
       
  1898 in part{constrs=constructors, rows=rows, A=[]}
       
  1899 end;
       
  1900 
       
  1901 (*---------------------------------------------------------------------------
       
  1902  * Misc. routines used in mk_case
       
  1903  *---------------------------------------------------------------------------*)
       
  1904 
       
  1905 fun mk_pat (c,l) =
       
  1906   let val L = length (binder_types (type_of c))
       
  1907       fun build (prfx,tag,plist) =
       
  1908           let val (args, plist') = chop L plist
       
  1909           in (prfx,tag,list_comb(c,args)::plist') end
       
  1910   in map build l end;
       
  1911 
       
  1912 fun v_to_prfx (prfx, v::pats) = (v::prfx,pats)
       
  1913   | v_to_prfx _ = raise TFL_ERR "mk_case" "v_to_prfx";
       
  1914 
       
  1915 fun v_to_pats (v::prfx,tag, pats) = (prfx, tag, v::pats)
       
  1916   | v_to_pats _ = raise TFL_ERR "mk_case" "v_to_pats";
       
  1917 
       
  1918 
       
  1919 (*----------------------------------------------------------------------------
       
  1920  * Translation of pattern terms into nested case expressions.
       
  1921  *
       
  1922  * This performs the translation and also builds the full set of patterns.
       
  1923  * Thus it supports the construction of induction theorems even when an
       
  1924  * incomplete set of patterns is given.
       
  1925  *---------------------------------------------------------------------------*)
       
  1926 
       
  1927 fun mk_case ty_info ty_match usednames range_ty =
       
  1928  let
       
  1929  fun mk_case_fail s = raise TFL_ERR "mk_case" s
       
  1930  val fresh_var = gvvariant usednames
       
  1931  val divide = partition fresh_var ty_match
       
  1932  fun expand constructors ty ((_,[]), _) = mk_case_fail"expand_var_row"
       
  1933    | expand constructors ty (row as ((prfx, p::rst), rhs)) =
       
  1934        if (is_Free p)
       
  1935        then let val fresh = fresh_constr ty_match ty fresh_var
       
  1936                 fun expnd (c,gvs) =
       
  1937                   let val capp = list_comb(c,gvs)
       
  1938                   in ((prfx, capp::rst), pattern_subst[(p,capp)] rhs)
       
  1939                   end
       
  1940             in map expnd (map fresh constructors)  end
       
  1941        else [row]
       
  1942  fun mk{rows=[],...} = mk_case_fail"no rows"
       
  1943    | mk{path=[], rows = ((prfx, []), (tm,tag))::_} =  (* Done *)
       
  1944         ([(prfx,tag,[])], tm)
       
  1945    | mk{path=[], rows = _::_} = mk_case_fail"blunder"
       
  1946    | mk{path as u::rstp, rows as ((prfx, []), rhs)::rst} =
       
  1947         mk{path = path,
       
  1948            rows = ((prfx, [fresh_var(type_of u)]), rhs)::rst}
       
  1949    | mk{path = u::rstp, rows as ((_, p::_), _)::_} =
       
  1950      let val (pat_rectangle,rights) = ListPair.unzip rows
       
  1951          val col0 = map(hd o #2) pat_rectangle
       
  1952      in
       
  1953      if (forall is_Free col0)
       
  1954      then let val rights' = map (fn(v,e) => pattern_subst[(v,u)] e)
       
  1955                                 (ListPair.zip (col0, rights))
       
  1956               val pat_rectangle' = map v_to_prfx pat_rectangle
       
  1957               val (pref_patl,tm) = mk{path = rstp,
       
  1958                                       rows = ListPair.zip (pat_rectangle',
       
  1959                                                            rights')}
       
  1960           in (map v_to_pats pref_patl, tm)
       
  1961           end
       
  1962      else
       
  1963      let val pty as Type (ty_name,_) = type_of p
       
  1964      in
       
  1965      case (ty_info ty_name)
       
  1966      of NONE => mk_case_fail("Not a known datatype: "^ty_name)
       
  1967       | SOME{case_const,constructors} =>
       
  1968         let
       
  1969             val case_const_name = #1(dest_Const case_const)
       
  1970             val nrows = maps (expand constructors pty) rows
       
  1971             val subproblems = divide(constructors, pty, range_ty, nrows)
       
  1972             val groups      = map #group subproblems
       
  1973             and new_formals = map #new_formals subproblems
       
  1974             and constructors' = map #constructor subproblems
       
  1975             val news = map (fn (nf,rows) => {path = nf@rstp, rows=rows})
       
  1976                            (ListPair.zip (new_formals, groups))
       
  1977             val rec_calls = map mk news
       
  1978             val (pat_rect,dtrees) = ListPair.unzip rec_calls
       
  1979             val case_functions = map USyntax.list_mk_abs
       
  1980                                   (ListPair.zip (new_formals, dtrees))
       
  1981             val types = map type_of (case_functions@[u]) @ [range_ty]
       
  1982             val case_const' = Const(case_const_name, list_mk_type types)
       
  1983             val tree = list_comb(case_const', case_functions@[u])
       
  1984             val pat_rect1 = flat (ListPair.map mk_pat (constructors', pat_rect))
       
  1985         in (pat_rect1,tree)
       
  1986         end
       
  1987      end end
       
  1988  in mk
       
  1989  end;
       
  1990 
       
  1991 
       
  1992 (* Repeated variable occurrences in a pattern are not allowed. *)
       
  1993 fun FV_multiset tm =
       
  1994    case (USyntax.dest_term tm)
       
  1995      of USyntax.VAR{Name = c, Ty = T} => [Free(c, T)]
       
  1996       | USyntax.CONST _ => []
       
  1997       | USyntax.COMB{Rator, Rand} => FV_multiset Rator @ FV_multiset Rand
       
  1998       | USyntax.LAMB _ => raise TFL_ERR "FV_multiset" "lambda";
       
  1999 
       
  2000 fun no_repeat_vars thy pat =
       
  2001  let fun check [] = true
       
  2002        | check (v::rst) =
       
  2003          if member (op aconv) rst v then
       
  2004             raise TFL_ERR "no_repeat_vars"
       
  2005                           (quote (#1 (dest_Free v)) ^
       
  2006                           " occurs repeatedly in the pattern " ^
       
  2007                           quote (Syntax.string_of_term_global thy pat))
       
  2008          else check rst
       
  2009  in check (FV_multiset pat)
       
  2010  end;
       
  2011 
       
  2012 fun dest_atom (Free p) = p
       
  2013   | dest_atom (Const p) = p
       
  2014   | dest_atom  _ = raise TFL_ERR "dest_atom" "function name not an identifier";
       
  2015 
       
  2016 fun same_name (p,q) = #1(dest_atom p) = #1(dest_atom q);
       
  2017 
       
  2018 local fun mk_functional_err s = raise TFL_ERR "mk_functional" s
       
  2019       fun single [_$_] =
       
  2020               mk_functional_err "recdef does not allow currying"
       
  2021         | single [f] = f
       
  2022         | single fs  =
       
  2023               (*multiple function names?*)
       
  2024               if length (distinct same_name fs) < length fs
       
  2025               then mk_functional_err
       
  2026                    "The function being declared appears with multiple types"
       
  2027               else mk_functional_err
       
  2028                    (string_of_int (length fs) ^
       
  2029                     " distinct function names being declared")
       
  2030 in
       
  2031 fun mk_functional thy clauses =
       
  2032  let val (L,R) = ListPair.unzip (map HOLogic.dest_eq clauses
       
  2033                    handle TERM _ => raise TFL_ERR "mk_functional"
       
  2034                         "recursion equations must use the = relation")
       
  2035      val (funcs,pats) = ListPair.unzip (map (fn (t$u) =>(t,u)) L)
       
  2036      val atom = single (distinct (op aconv) funcs)
       
  2037      val (fname,ftype) = dest_atom atom
       
  2038      val dummy = map (no_repeat_vars thy) pats
       
  2039      val rows = ListPair.zip (map (fn x => ([]:term list,[x])) pats,
       
  2040                               map_index (fn (i, t) => (t,(i,true))) R)
       
  2041      val names = List.foldr Misc_Legacy.add_term_names [] R
       
  2042      val atype = type_of(hd pats)
       
  2043      and aname = singleton (Name.variant_list names) "a"
       
  2044      val a = Free(aname,atype)
       
  2045      val ty_info = Thry.match_info thy
       
  2046      val ty_match = Thry.match_type thy
       
  2047      val range_ty = type_of (hd R)
       
  2048      val (patts, case_tm) = mk_case ty_info ty_match (aname::names) range_ty
       
  2049                                     {path=[a], rows=rows}
       
  2050      val patts1 = map (fn (_,tag,[pat]) => (pat,tag)) patts
       
  2051           handle Match => mk_functional_err "error in pattern-match translation"
       
  2052      val patts2 = Library.sort (Library.int_ord o apply2 row_of_pat) patts1
       
  2053      val finals = map row_of_pat patts2
       
  2054      val originals = map (row_of_pat o #2) rows
       
  2055      val dummy = case (subtract (op =) finals originals)
       
  2056              of [] => ()
       
  2057           | L => mk_functional_err
       
  2058  ("The following clauses are redundant (covered by preceding clauses): " ^
       
  2059                    commas (map (fn i => string_of_int (i + 1)) L))
       
  2060  in {functional = Abs(Long_Name.base_name fname, ftype,
       
  2061                       abstract_over (atom, absfree (aname,atype) case_tm)),
       
  2062      pats = patts2}
       
  2063 end end;
       
  2064 
       
  2065 
       
  2066 (*----------------------------------------------------------------------------
       
  2067  *
       
  2068  *                    PRINCIPLES OF DEFINITION
       
  2069  *
       
  2070  *---------------------------------------------------------------------------*)
       
  2071 
       
  2072 
       
  2073 (*For Isabelle, the lhs of a definition must be a constant.*)
       
  2074 fun const_def sign (c, Ty, rhs) =
       
  2075   singleton (Syntax.check_terms (Proof_Context.init_global sign))
       
  2076     (Const(@{const_name Pure.eq},dummyT) $ Const(c,Ty) $ rhs);
       
  2077 
       
  2078 (*Make all TVars available for instantiation by adding a ? to the front*)
       
  2079 fun poly_tvars (Type(a,Ts)) = Type(a, map (poly_tvars) Ts)
       
  2080   | poly_tvars (TFree (a,sort)) = TVar (("?" ^ a, 0), sort)
       
  2081   | poly_tvars (TVar ((a,i),sort)) = TVar (("?" ^ a, i+1), sort);
       
  2082 
       
  2083 local
       
  2084   val f_eq_wfrec_R_M =
       
  2085     #ant(USyntax.dest_imp(#2(USyntax.strip_forall (concl Thms.WFREC_COROLLARY))))
       
  2086   val {lhs=f, rhs} = USyntax.dest_eq f_eq_wfrec_R_M
       
  2087   val (fname,_) = dest_Free f
       
  2088   val (wfrec,_) = USyntax.strip_comb rhs
       
  2089 in
       
  2090 
       
  2091 fun wfrec_definition0 fid R (functional as Abs(x, Ty, _)) thy =
       
  2092   let
       
  2093     val def_name = Thm.def_name (Long_Name.base_name fid)
       
  2094     val wfrec_R_M = map_types poly_tvars (wfrec $ map_types poly_tvars R) $ functional
       
  2095     val def_term = const_def thy (fid, Ty, wfrec_R_M)
       
  2096     val ([def], thy') =
       
  2097       Global_Theory.add_defs false [Thm.no_attributes (Binding.name def_name, def_term)] thy
       
  2098   in (def, thy') end;
       
  2099 
       
  2100 end;
       
  2101 
       
  2102 
       
  2103 
       
  2104 (*---------------------------------------------------------------------------
       
  2105  * This structure keeps track of congruence rules that aren't derived
       
  2106  * from a datatype definition.
       
  2107  *---------------------------------------------------------------------------*)
       
  2108 fun extraction_thms thy =
       
  2109  let val {case_rewrites,case_congs} = Thry.extract_info thy
       
  2110  in (case_rewrites, case_congs)
       
  2111  end;
       
  2112 
       
  2113 
       
  2114 (*---------------------------------------------------------------------------
       
  2115  * Pair patterns with termination conditions. The full list of patterns for
       
  2116  * a definition is merged with the TCs arising from the user-given clauses.
       
  2117  * There can be fewer clauses than the full list, if the user omitted some
       
  2118  * cases. This routine is used to prepare input for mk_induction.
       
  2119  *---------------------------------------------------------------------------*)
       
  2120 fun merge full_pats TCs =
       
  2121 let fun insert (p,TCs) =
       
  2122       let fun insrt ((x as (h,[]))::rst) =
       
  2123                  if (p aconv h) then (p,TCs)::rst else x::insrt rst
       
  2124             | insrt (x::rst) = x::insrt rst
       
  2125             | insrt[] = raise TFL_ERR "merge.insert" "pattern not found"
       
  2126       in insrt end
       
  2127     fun pass ([],ptcl_final) = ptcl_final
       
  2128       | pass (ptcs::tcl, ptcl) = pass(tcl, insert ptcs ptcl)
       
  2129 in
       
  2130   pass (TCs, map (fn p => (p,[])) full_pats)
       
  2131 end;
       
  2132 
       
  2133 
       
  2134 fun givens pats = map pat_of (filter given pats);
       
  2135 
       
  2136 fun post_definition ctxt meta_tflCongs (def, pats) =
       
  2137  let val thy = Proof_Context.theory_of ctxt
       
  2138      val tych = Thry.typecheck thy
       
  2139      val f = #lhs(USyntax.dest_eq(concl def))
       
  2140      val corollary = Rules.MATCH_MP Thms.WFREC_COROLLARY def
       
  2141      val pats' = filter given pats
       
  2142      val given_pats = map pat_of pats'
       
  2143      val rows = map row_of_pat pats'
       
  2144      val WFR = #ant(USyntax.dest_imp(concl corollary))
       
  2145      val R = #Rand(USyntax.dest_comb WFR)
       
  2146      val corollary' = Rules.UNDISCH corollary  (* put WF R on assums *)
       
  2147      val corollaries = map (fn pat => Rules.SPEC (tych pat) corollary') given_pats
       
  2148      val (case_rewrites,context_congs) = extraction_thms thy
       
  2149      (*case_ss causes minimal simplification: bodies of case expressions are
       
  2150        not simplified. Otherwise large examples (Red-Black trees) are too
       
  2151        slow.*)
       
  2152      val case_simpset =
       
  2153        put_simpset HOL_basic_ss ctxt
       
  2154           addsimps case_rewrites
       
  2155           |> fold (Simplifier.add_cong o #case_cong_weak o snd)
       
  2156               (Symtab.dest (BNF_LFP_Compat.get_all thy [BNF_LFP_Compat.Keep_Nesting]))
       
  2157      val corollaries' = map (Simplifier.simplify case_simpset) corollaries
       
  2158      val extract =
       
  2159       Rules.CONTEXT_REWRITE_RULE ctxt (f, [R], @{thm cut_apply}, meta_tflCongs @ context_congs)
       
  2160      val (rules, TCs) = ListPair.unzip (map extract corollaries')
       
  2161      val rules0 = map (rewrite_rule ctxt [Thms.CUT_DEF]) rules
       
  2162      val mk_cond_rule = Rules.FILTER_DISCH_ALL(not o curry (op aconv) WFR)
       
  2163      val rules1 = Rules.LIST_CONJ(map mk_cond_rule rules0)
       
  2164  in
       
  2165  {rules = rules1,
       
  2166   rows = rows,
       
  2167   full_pats_TCs = merge (map pat_of pats) (ListPair.zip (given_pats, TCs)),
       
  2168   TCs = TCs}
       
  2169  end;
       
  2170 
       
  2171 
       
  2172 (*---------------------------------------------------------------------------
       
  2173  * Perform the extraction without making the definition. Definition and
       
  2174  * extraction commute for the non-nested case.  (Deferred recdefs)
       
  2175  *
       
  2176  * The purpose of wfrec_eqns is merely to instantiate the recursion theorem
       
  2177  * and extract termination conditions: no definition is made.
       
  2178  *---------------------------------------------------------------------------*)
       
  2179 
       
  2180 fun wfrec_eqns thy fid tflCongs eqns =
       
  2181  let val ctxt = Proof_Context.init_global thy
       
  2182      val {lhs,rhs} = USyntax.dest_eq (hd eqns)
       
  2183      val (f,args) = USyntax.strip_comb lhs
       
  2184      val (fname,fty) = dest_atom f
       
  2185      val (SV,a) = front_last args    (* SV = schematic variables *)
       
  2186      val g = list_comb(f,SV)
       
  2187      val h = Free(fname,type_of g)
       
  2188      val eqns1 = map (subst_free[(g,h)]) eqns
       
  2189      val {functional as Abs(x, Ty, _),  pats} = mk_functional thy eqns1
       
  2190      val given_pats = givens pats
       
  2191      (* val f = Free(x,Ty) *)
       
  2192      val Type("fun", [f_dty, f_rty]) = Ty
       
  2193      val dummy = if x<>fid then
       
  2194                         raise TFL_ERR "wfrec_eqns"
       
  2195                                       ("Expected a definition of " ^
       
  2196                                       quote fid ^ " but found one of " ^
       
  2197                                       quote x)
       
  2198                  else ()
       
  2199      val (case_rewrites,context_congs) = extraction_thms thy
       
  2200      val tych = Thry.typecheck thy
       
  2201      val WFREC_THM0 = Rules.ISPEC (tych functional) Thms.WFREC_COROLLARY
       
  2202      val Const(@{const_name All},_) $ Abs(Rname,Rtype,_) = concl WFREC_THM0
       
  2203      val R = Free (singleton (Name.variant_list (List.foldr Misc_Legacy.add_term_names [] eqns)) Rname,
       
  2204                    Rtype)
       
  2205      val WFREC_THM = Rules.ISPECL [tych R, tych g] WFREC_THM0
       
  2206      val ([proto_def, WFR],_) = USyntax.strip_imp(concl WFREC_THM)
       
  2207      val dummy =
       
  2208            if !trace then
       
  2209                writeln ("ORIGINAL PROTO_DEF: " ^
       
  2210                           Syntax.string_of_term_global thy proto_def)
       
  2211            else ()
       
  2212      val R1 = USyntax.rand WFR
       
  2213      val corollary' = Rules.UNDISCH (Rules.UNDISCH WFREC_THM)
       
  2214      val corollaries = map (fn pat => Rules.SPEC (tych pat) corollary') given_pats
       
  2215      val corollaries' = map (rewrite_rule ctxt case_rewrites) corollaries
       
  2216      val extract =
       
  2217       Rules.CONTEXT_REWRITE_RULE ctxt (f, R1::SV, @{thm cut_apply}, tflCongs @ context_congs)
       
  2218  in {proto_def = proto_def,
       
  2219      SV=SV,
       
  2220      WFR=WFR,
       
  2221      pats=pats,
       
  2222      extracta = map extract corollaries'}
       
  2223  end;
       
  2224 
       
  2225 
       
  2226 (*---------------------------------------------------------------------------
       
  2227  * Define the constant after extracting the termination conditions. The
       
  2228  * wellfounded relation used in the definition is computed by using the
       
  2229  * choice operator on the extracted conditions (plus the condition that
       
  2230  * such a relation must be wellfounded).
       
  2231  *---------------------------------------------------------------------------*)
       
  2232 
       
  2233 fun lazyR_def thy fid tflCongs eqns =
       
  2234  let val {proto_def,WFR,pats,extracta,SV} =
       
  2235            wfrec_eqns thy fid tflCongs eqns
       
  2236      val R1 = USyntax.rand WFR
       
  2237      val f = #lhs(USyntax.dest_eq proto_def)
       
  2238      val (extractants,TCl) = ListPair.unzip extracta
       
  2239      val dummy = if !trace
       
  2240                  then writeln (cat_lines ("Extractants =" ::
       
  2241                   map (Display.string_of_thm_global thy) extractants))
       
  2242                  else ()
       
  2243      val TCs = fold_rev (union (op aconv)) TCl []
       
  2244      val full_rqt = WFR::TCs
       
  2245      val R' = USyntax.mk_select{Bvar=R1, Body=USyntax.list_mk_conj full_rqt}
       
  2246      val R'abs = USyntax.rand R'
       
  2247      val proto_def' = subst_free[(R1,R')] proto_def
       
  2248      val dummy = if !trace then writeln ("proto_def' = " ^
       
  2249                                          Syntax.string_of_term_global
       
  2250                                          thy proto_def')
       
  2251                            else ()
       
  2252      val {lhs,rhs} = USyntax.dest_eq proto_def'
       
  2253      val (c,args) = USyntax.strip_comb lhs
       
  2254      val (name,Ty) = dest_atom c
       
  2255      val defn = const_def thy (name, Ty, USyntax.list_mk_abs (args,rhs))
       
  2256      val ([def0], thy') =
       
  2257        thy
       
  2258        |> Global_Theory.add_defs false
       
  2259             [Thm.no_attributes (Binding.name (Thm.def_name fid), defn)]
       
  2260      val def = Thm.unvarify_global def0;
       
  2261      val ctxt' = Syntax.init_pretty_global thy';
       
  2262      val dummy =
       
  2263        if !trace then writeln ("DEF = " ^ Display.string_of_thm ctxt' def)
       
  2264        else ()
       
  2265      (* val fconst = #lhs(USyntax.dest_eq(concl def))  *)
       
  2266      val tych = Thry.typecheck thy'
       
  2267      val full_rqt_prop = map (Dcterm.mk_prop o tych) full_rqt
       
  2268          (*lcp: a lot of object-logic inference to remove*)
       
  2269      val baz = Rules.DISCH_ALL
       
  2270                  (fold_rev Rules.DISCH full_rqt_prop
       
  2271                   (Rules.LIST_CONJ extractants))
       
  2272      val dum = if !trace then writeln ("baz = " ^ Display.string_of_thm ctxt' baz) else ()
       
  2273      val f_free = Free (fid, fastype_of f)  (*'cos f is a Const*)
       
  2274      val SV' = map tych SV;
       
  2275      val SVrefls = map Thm.reflexive SV'
       
  2276      val def0 = (fold (fn x => fn th => Rules.rbeta(Thm.combination th x))
       
  2277                    SVrefls def)
       
  2278                 RS meta_eq_to_obj_eq
       
  2279      val def' = Rules.MP (Rules.SPEC (tych R') (Rules.GEN ctxt' (tych R1) baz)) def0
       
  2280      val body_th = Rules.LIST_CONJ (map Rules.ASSUME full_rqt_prop)
       
  2281      val SELECT_AX = (*in this way we hope to avoid a STATIC dependence upon
       
  2282                        theory Hilbert_Choice*)
       
  2283          ML_Context.thm "Hilbert_Choice.tfl_some"
       
  2284          handle ERROR msg => cat_error msg
       
  2285     "defer_recdef requires theory Main or at least Hilbert_Choice as parent"
       
  2286      val bar = Rules.MP (Rules.ISPECL[tych R'abs, tych R1] SELECT_AX) body_th
       
  2287  in {theory = thy', R=R1, SV=SV,
       
  2288      rules = fold (fn a => fn b => Rules.MP b a) (Rules.CONJUNCTS bar) def',
       
  2289      full_pats_TCs = merge (map pat_of pats) (ListPair.zip (givens pats, TCl)),
       
  2290      patterns = pats}
       
  2291  end;
       
  2292 
       
  2293 
       
  2294 
       
  2295 (*----------------------------------------------------------------------------
       
  2296  *
       
  2297  *                           INDUCTION THEOREM
       
  2298  *
       
  2299  *---------------------------------------------------------------------------*)
       
  2300 
       
  2301 
       
  2302 (*------------------------  Miscellaneous function  --------------------------
       
  2303  *
       
  2304  *           [x_1,...,x_n]     ?v_1...v_n. M[v_1,...,v_n]
       
  2305  *     -----------------------------------------------------------
       
  2306  *     ( M[x_1,...,x_n], [(x_i,?v_1...v_n. M[v_1,...,v_n]),
       
  2307  *                        ...
       
  2308  *                        (x_j,?v_n. M[x_1,...,x_(n-1),v_n])] )
       
  2309  *
       
  2310  * This function is totally ad hoc. Used in the production of the induction
       
  2311  * theorem. The nchotomy theorem can have clauses that look like
       
  2312  *
       
  2313  *     ?v1..vn. z = C vn..v1
       
  2314  *
       
  2315  * in which the order of quantification is not the order of occurrence of the
       
  2316  * quantified variables as arguments to C. Since we have no control over this
       
  2317  * aspect of the nchotomy theorem, we make the correspondence explicit by
       
  2318  * pairing the incoming new variable with the term it gets beta-reduced into.
       
  2319  *---------------------------------------------------------------------------*)
       
  2320 
       
  2321 fun alpha_ex_unroll (xlist, tm) =
       
  2322   let val (qvars,body) = USyntax.strip_exists tm
       
  2323       val vlist = #2 (USyntax.strip_comb (USyntax.rhs body))
       
  2324       val plist = ListPair.zip (vlist, xlist)
       
  2325       val args = map (the o AList.lookup (op aconv) plist) qvars
       
  2326                    handle Option.Option => raise Fail "TFL.alpha_ex_unroll: no correspondence"
       
  2327       fun build ex      []   = []
       
  2328         | build (_$rex) (v::rst) =
       
  2329            let val ex1 = Term.betapply(rex, v)
       
  2330            in  ex1 :: build ex1 rst
       
  2331            end
       
  2332      val (nex::exl) = rev (tm::build tm args)
       
  2333   in
       
  2334   (nex, ListPair.zip (args, rev exl))
       
  2335   end;
       
  2336 
       
  2337 
       
  2338 
       
  2339 (*----------------------------------------------------------------------------
       
  2340  *
       
  2341  *             PROVING COMPLETENESS OF PATTERNS
       
  2342  *
       
  2343  *---------------------------------------------------------------------------*)
       
  2344 
       
  2345 fun mk_case ty_info usednames thy =
       
  2346  let
       
  2347  val ctxt = Proof_Context.init_global thy
       
  2348  val divide = ipartition (gvvariant usednames)
       
  2349  val tych = Thry.typecheck thy
       
  2350  fun tych_binding(x,y) = (tych x, tych y)
       
  2351  fun fail s = raise TFL_ERR "mk_case" s
       
  2352  fun mk{rows=[],...} = fail"no rows"
       
  2353    | mk{path=[], rows = [([], (thm, bindings))]} =
       
  2354                          Rules.IT_EXISTS ctxt (map tych_binding bindings) thm
       
  2355    | mk{path = u::rstp, rows as (p::_, _)::_} =
       
  2356      let val (pat_rectangle,rights) = ListPair.unzip rows
       
  2357          val col0 = map hd pat_rectangle
       
  2358          val pat_rectangle' = map tl pat_rectangle
       
  2359      in
       
  2360      if (forall is_Free col0) (* column 0 is all variables *)
       
  2361      then let val rights' = map (fn ((thm,theta),v) => (thm,theta@[(u,v)]))
       
  2362                                 (ListPair.zip (rights, col0))
       
  2363           in mk{path = rstp, rows = ListPair.zip (pat_rectangle', rights')}
       
  2364           end
       
  2365      else                     (* column 0 is all constructors *)
       
  2366      let val Type (ty_name,_) = type_of p
       
  2367      in
       
  2368      case (ty_info ty_name)
       
  2369      of NONE => fail("Not a known datatype: "^ty_name)
       
  2370       | SOME{constructors,nchotomy} =>
       
  2371         let val thm' = Rules.ISPEC (tych u) nchotomy
       
  2372             val disjuncts = USyntax.strip_disj (concl thm')
       
  2373             val subproblems = divide(constructors, rows)
       
  2374             val groups      = map #group subproblems
       
  2375             and new_formals = map #new_formals subproblems
       
  2376             val existentials = ListPair.map alpha_ex_unroll
       
  2377                                    (new_formals, disjuncts)
       
  2378             val constraints = map #1 existentials
       
  2379             val vexl = map #2 existentials
       
  2380             fun expnd tm (pats,(th,b)) = (pats, (Rules.SUBS ctxt [Rules.ASSUME (tych tm)] th, b))
       
  2381             val news = map (fn (nf,rows,c) => {path = nf@rstp,
       
  2382                                                rows = map (expnd c) rows})
       
  2383                            (Utils.zip3 new_formals groups constraints)
       
  2384             val recursive_thms = map mk news
       
  2385             val build_exists = Library.foldr
       
  2386                                 (fn((x,t), th) =>
       
  2387                                  Rules.CHOOSE ctxt (tych x, Rules.ASSUME (tych t)) th)
       
  2388             val thms' = ListPair.map build_exists (vexl, recursive_thms)
       
  2389             val same_concls = Rules.EVEN_ORS thms'
       
  2390         in Rules.DISJ_CASESL thm' same_concls
       
  2391         end
       
  2392      end end
       
  2393  in mk
       
  2394  end;
       
  2395 
       
  2396 
       
  2397 fun complete_cases thy =
       
  2398  let val ctxt = Proof_Context.init_global thy
       
  2399      val tych = Thry.typecheck thy
       
  2400      val ty_info = Thry.induct_info thy
       
  2401  in fn pats =>
       
  2402  let val names = List.foldr Misc_Legacy.add_term_names [] pats
       
  2403      val T = type_of (hd pats)
       
  2404      val aname = singleton (Name.variant_list names) "a"
       
  2405      val vname = singleton (Name.variant_list (aname::names)) "v"
       
  2406      val a = Free (aname, T)
       
  2407      val v = Free (vname, T)
       
  2408      val a_eq_v = HOLogic.mk_eq(a,v)
       
  2409      val ex_th0 = Rules.EXISTS (tych (USyntax.mk_exists{Bvar=v,Body=a_eq_v}), tych a)
       
  2410                            (Rules.REFL (tych a))
       
  2411      val th0 = Rules.ASSUME (tych a_eq_v)
       
  2412      val rows = map (fn x => ([x], (th0,[]))) pats
       
  2413  in
       
  2414  Rules.GEN ctxt (tych a)
       
  2415        (Rules.RIGHT_ASSOC ctxt
       
  2416           (Rules.CHOOSE ctxt (tych v, ex_th0)
       
  2417                 (mk_case ty_info (vname::aname::names)
       
  2418                  thy {path=[v], rows=rows})))
       
  2419  end end;
       
  2420 
       
  2421 
       
  2422 (*---------------------------------------------------------------------------
       
  2423  * Constructing induction hypotheses: one for each recursive call.
       
  2424  *
       
  2425  * Note. R will never occur as a variable in the ind_clause, because
       
  2426  * to do so, it would have to be from a nested definition, and we don't
       
  2427  * allow nested defns to have R variable.
       
  2428  *
       
  2429  * Note. When the context is empty, there can be no local variables.
       
  2430  *---------------------------------------------------------------------------*)
       
  2431 (*
       
  2432 local infix 5 ==>
       
  2433       fun (tm1 ==> tm2) = USyntax.mk_imp{ant = tm1, conseq = tm2}
       
  2434 in
       
  2435 fun build_ih f P (pat,TCs) =
       
  2436  let val globals = USyntax.free_vars_lr pat
       
  2437      fun nested tm = is_some (USyntax.find_term (curry (op aconv) f) tm)
       
  2438      fun dest_TC tm =
       
  2439          let val (cntxt,R_y_pat) = USyntax.strip_imp(#2(USyntax.strip_forall tm))
       
  2440              val (R,y,_) = USyntax.dest_relation R_y_pat
       
  2441              val P_y = if (nested tm) then R_y_pat ==> P$y else P$y
       
  2442          in case cntxt
       
  2443               of [] => (P_y, (tm,[]))
       
  2444                | _  => let
       
  2445                     val imp = USyntax.list_mk_conj cntxt ==> P_y
       
  2446                     val lvs = gen_rems (op aconv) (USyntax.free_vars_lr imp, globals)
       
  2447                     val locals = #2(Utils.pluck (curry (op aconv) P) lvs) handle Utils.ERR _ => lvs
       
  2448                     in (USyntax.list_mk_forall(locals,imp), (tm,locals)) end
       
  2449          end
       
  2450  in case TCs
       
  2451     of [] => (USyntax.list_mk_forall(globals, P$pat), [])
       
  2452      |  _ => let val (ihs, TCs_locals) = ListPair.unzip(map dest_TC TCs)
       
  2453                  val ind_clause = USyntax.list_mk_conj ihs ==> P$pat
       
  2454              in (USyntax.list_mk_forall(globals,ind_clause), TCs_locals)
       
  2455              end
       
  2456  end
       
  2457 end;
       
  2458 *)
       
  2459 
       
  2460 local infix 5 ==>
       
  2461       fun (tm1 ==> tm2) = USyntax.mk_imp{ant = tm1, conseq = tm2}
       
  2462 in
       
  2463 fun build_ih f (P,SV) (pat,TCs) =
       
  2464  let val pat_vars = USyntax.free_vars_lr pat
       
  2465      val globals = pat_vars@SV
       
  2466      fun nested tm = is_some (USyntax.find_term (curry (op aconv) f) tm)
       
  2467      fun dest_TC tm =
       
  2468          let val (cntxt,R_y_pat) = USyntax.strip_imp(#2(USyntax.strip_forall tm))
       
  2469              val (R,y,_) = USyntax.dest_relation R_y_pat
       
  2470              val P_y = if (nested tm) then R_y_pat ==> P$y else P$y
       
  2471          in case cntxt
       
  2472               of [] => (P_y, (tm,[]))
       
  2473                | _  => let
       
  2474                     val imp = USyntax.list_mk_conj cntxt ==> P_y
       
  2475                     val lvs = subtract (op aconv) globals (USyntax.free_vars_lr imp)
       
  2476                     val locals = #2(Utils.pluck (curry (op aconv) P) lvs) handle Utils.ERR _ => lvs
       
  2477                     in (USyntax.list_mk_forall(locals,imp), (tm,locals)) end
       
  2478          end
       
  2479  in case TCs
       
  2480     of [] => (USyntax.list_mk_forall(pat_vars, P$pat), [])
       
  2481      |  _ => let val (ihs, TCs_locals) = ListPair.unzip(map dest_TC TCs)
       
  2482                  val ind_clause = USyntax.list_mk_conj ihs ==> P$pat
       
  2483              in (USyntax.list_mk_forall(pat_vars,ind_clause), TCs_locals)
       
  2484              end
       
  2485  end
       
  2486 end;
       
  2487 
       
  2488 (*---------------------------------------------------------------------------
       
  2489  * This function makes good on the promise made in "build_ih".
       
  2490  *
       
  2491  * Input  is tm = "(!y. R y pat ==> P y) ==> P pat",
       
  2492  *           TCs = TC_1[pat] ... TC_n[pat]
       
  2493  *           thm = ih1 /\ ... /\ ih_n |- ih[pat]
       
  2494  *---------------------------------------------------------------------------*)
       
  2495 fun prove_case ctxt f (tm,TCs_locals,thm) =
       
  2496  let val tych = Thry.typecheck (Proof_Context.theory_of ctxt)
       
  2497      val antc = tych(#ant(USyntax.dest_imp tm))
       
  2498      val thm' = Rules.SPEC_ALL thm
       
  2499      fun nested tm = is_some (USyntax.find_term (curry (op aconv) f) tm)
       
  2500      fun get_cntxt TC = tych(#ant(USyntax.dest_imp(#2(USyntax.strip_forall(concl TC)))))
       
  2501      fun mk_ih ((TC,locals),th2,nested) =
       
  2502          Rules.GENL ctxt (map tych locals)
       
  2503             (if nested then Rules.DISCH (get_cntxt TC) th2 handle Utils.ERR _ => th2
       
  2504              else if USyntax.is_imp (concl TC) then Rules.IMP_TRANS TC th2
       
  2505              else Rules.MP th2 TC)
       
  2506  in
       
  2507  Rules.DISCH antc
       
  2508  (if USyntax.is_imp(concl thm') (* recursive calls in this clause *)
       
  2509   then let val th1 = Rules.ASSUME antc
       
  2510            val TCs = map #1 TCs_locals
       
  2511            val ylist = map (#2 o USyntax.dest_relation o #2 o USyntax.strip_imp o
       
  2512                             #2 o USyntax.strip_forall) TCs
       
  2513            val TClist = map (fn(TC,lvs) => (Rules.SPEC_ALL(Rules.ASSUME(tych TC)),lvs))
       
  2514                             TCs_locals
       
  2515            val th2list = map (fn t => Rules.SPEC (tych t) th1) ylist
       
  2516            val nlist = map nested TCs
       
  2517            val triples = Utils.zip3 TClist th2list nlist
       
  2518            val Pylist = map mk_ih triples
       
  2519        in Rules.MP thm' (Rules.LIST_CONJ Pylist) end
       
  2520   else thm')
       
  2521  end;
       
  2522 
       
  2523 
       
  2524 (*---------------------------------------------------------------------------
       
  2525  *
       
  2526  *         x = (v1,...,vn)  |- M[x]
       
  2527  *    ---------------------------------------------
       
  2528  *      ?v1 ... vn. x = (v1,...,vn) |- M[x]
       
  2529  *
       
  2530  *---------------------------------------------------------------------------*)
       
  2531 fun LEFT_ABS_VSTRUCT ctxt tych thm =
       
  2532   let fun CHOOSER v (tm,thm) =
       
  2533         let val ex_tm = USyntax.mk_exists{Bvar=v,Body=tm}
       
  2534         in (ex_tm, Rules.CHOOSE ctxt (tych v, Rules.ASSUME (tych ex_tm)) thm)
       
  2535         end
       
  2536       val [veq] = filter (can USyntax.dest_eq) (#1 (Rules.dest_thm thm))
       
  2537       val {lhs,rhs} = USyntax.dest_eq veq
       
  2538       val L = USyntax.free_vars_lr rhs
       
  2539   in  #2 (fold_rev CHOOSER L (veq,thm))  end;
       
  2540 
       
  2541 
       
  2542 (*----------------------------------------------------------------------------
       
  2543  * Input : f, R,  and  [(pat1,TCs1),..., (patn,TCsn)]
       
  2544  *
       
  2545  * Instantiates WF_INDUCTION_THM, getting Sinduct and then tries to prove
       
  2546  * recursion induction (Rinduct) by proving the antecedent of Sinduct from
       
  2547  * the antecedent of Rinduct.
       
  2548  *---------------------------------------------------------------------------*)
       
  2549 fun mk_induction thy {fconst, R, SV, pat_TCs_list} =
       
  2550 let val ctxt = Proof_Context.init_global thy
       
  2551     val tych = Thry.typecheck thy
       
  2552     val Sinduction = Rules.UNDISCH (Rules.ISPEC (tych R) Thms.WF_INDUCTION_THM)
       
  2553     val (pats,TCsl) = ListPair.unzip pat_TCs_list
       
  2554     val case_thm = complete_cases thy pats
       
  2555     val domain = (type_of o hd) pats
       
  2556     val Pname = singleton (Name.variant_list (List.foldr (Library.foldr Misc_Legacy.add_term_names)
       
  2557                               [] (pats::TCsl))) "P"
       
  2558     val P = Free(Pname, domain --> HOLogic.boolT)
       
  2559     val Sinduct = Rules.SPEC (tych P) Sinduction
       
  2560     val Sinduct_assumf = USyntax.rand ((#ant o USyntax.dest_imp o concl) Sinduct)
       
  2561     val Rassums_TCl' = map (build_ih fconst (P,SV)) pat_TCs_list
       
  2562     val (Rassums,TCl') = ListPair.unzip Rassums_TCl'
       
  2563     val Rinduct_assum = Rules.ASSUME (tych (USyntax.list_mk_conj Rassums))
       
  2564     val cases = map (fn pat => Term.betapply (Sinduct_assumf, pat)) pats
       
  2565     val tasks = Utils.zip3 cases TCl' (Rules.CONJUNCTS Rinduct_assum)
       
  2566     val proved_cases = map (prove_case ctxt fconst) tasks
       
  2567     val v =
       
  2568       Free (singleton
       
  2569         (Name.variant_list (List.foldr Misc_Legacy.add_term_names [] (map concl proved_cases))) "v",
       
  2570           domain)
       
  2571     val vtyped = tych v
       
  2572     val substs = map (Rules.SYM o Rules.ASSUME o tych o (curry HOLogic.mk_eq v)) pats
       
  2573     val proved_cases1 = ListPair.map (fn (th,th') => Rules.SUBS ctxt [th]th')
       
  2574                           (substs, proved_cases)
       
  2575     val abs_cases = map (LEFT_ABS_VSTRUCT ctxt tych) proved_cases1
       
  2576     val dant = Rules.GEN ctxt vtyped (Rules.DISJ_CASESL (Rules.ISPEC vtyped case_thm) abs_cases)
       
  2577     val dc = Rules.MP Sinduct dant
       
  2578     val Parg_ty = type_of(#Bvar(USyntax.dest_forall(concl dc)))
       
  2579     val vars = map (gvvariant[Pname]) (USyntax.strip_prod_type Parg_ty)
       
  2580     val dc' = fold_rev (Rules.GEN ctxt o tych) vars
       
  2581                        (Rules.SPEC (tych(USyntax.mk_vstruct Parg_ty vars)) dc)
       
  2582 in
       
  2583    Rules.GEN ctxt (tych P) (Rules.DISCH (tych(concl Rinduct_assum)) dc')
       
  2584 end
       
  2585 handle Utils.ERR _ => raise TFL_ERR "mk_induction" "failed derivation";
       
  2586 
       
  2587 
       
  2588 
       
  2589 
       
  2590 (*---------------------------------------------------------------------------
       
  2591  *
       
  2592  *                        POST PROCESSING
       
  2593  *
       
  2594  *---------------------------------------------------------------------------*)
       
  2595 
       
  2596 
       
  2597 fun simplify_induction thy hth ind =
       
  2598   let val tych = Thry.typecheck thy
       
  2599       val (asl,_) = Rules.dest_thm ind
       
  2600       val (_,tc_eq_tc') = Rules.dest_thm hth
       
  2601       val tc = USyntax.lhs tc_eq_tc'
       
  2602       fun loop [] = ind
       
  2603         | loop (asm::rst) =
       
  2604           if (can (Thry.match_term thy asm) tc)
       
  2605           then Rules.UNDISCH
       
  2606                  (Rules.MATCH_MP
       
  2607                      (Rules.MATCH_MP Thms.simp_thm (Rules.DISCH (tych asm) ind))
       
  2608                      hth)
       
  2609          else loop rst
       
  2610   in loop asl
       
  2611 end;
       
  2612 
       
  2613 
       
  2614 (*---------------------------------------------------------------------------
       
  2615  * The termination condition is an antecedent to the rule, and an
       
  2616  * assumption to the theorem.
       
  2617  *---------------------------------------------------------------------------*)
       
  2618 fun elim_tc tcthm (rule,induction) =
       
  2619    (Rules.MP rule tcthm, Rules.PROVE_HYP tcthm induction)
       
  2620 
       
  2621 
       
  2622 fun trace_thms ctxt s L =
       
  2623   if !trace then writeln (cat_lines (s :: map (Display.string_of_thm ctxt) L))
       
  2624   else ();
       
  2625 
       
  2626 fun trace_cterm ctxt s ct =
       
  2627   if !trace then
       
  2628     writeln (cat_lines [s, Syntax.string_of_term ctxt (Thm.term_of ct)])
       
  2629   else ();
       
  2630 
       
  2631 
       
  2632 fun postprocess ctxt strict {wf_tac, terminator, simplifier} {rules,induction,TCs} =
       
  2633   let
       
  2634     val thy = Proof_Context.theory_of ctxt;
       
  2635     val tych = Thry.typecheck thy;
       
  2636 
       
  2637    (*---------------------------------------------------------------------
       
  2638     * Attempt to eliminate WF condition. It's the only assumption of rules
       
  2639     *---------------------------------------------------------------------*)
       
  2640     val (rules1,induction1)  =
       
  2641        let val thm =
       
  2642         Rules.prove ctxt strict (HOLogic.mk_Trueprop (hd(#1(Rules.dest_thm rules))), wf_tac)
       
  2643        in (Rules.PROVE_HYP thm rules, Rules.PROVE_HYP thm induction)
       
  2644        end handle Utils.ERR _ => (rules,induction);
       
  2645 
       
  2646    (*----------------------------------------------------------------------
       
  2647     * The termination condition (tc) is simplified to |- tc = tc' (there
       
  2648     * might not be a change!) and then 3 attempts are made:
       
  2649     *
       
  2650     *   1. if |- tc = T, then eliminate it with eqT; otherwise,
       
  2651     *   2. apply the terminator to tc'. If |- tc' = T then eliminate; else
       
  2652     *   3. replace tc by tc' in both the rules and the induction theorem.
       
  2653     *---------------------------------------------------------------------*)
       
  2654 
       
  2655    fun simplify_tc tc (r,ind) =
       
  2656        let val tc1 = tych tc
       
  2657            val _ = trace_cterm ctxt "TC before simplification: " tc1
       
  2658            val tc_eq = simplifier tc1
       
  2659            val _ = trace_thms ctxt "result: " [tc_eq]
       
  2660        in
       
  2661        elim_tc (Rules.MATCH_MP Thms.eqT tc_eq) (r,ind)
       
  2662        handle Utils.ERR _ =>
       
  2663         (elim_tc (Rules.MATCH_MP(Rules.MATCH_MP Thms.rev_eq_mp tc_eq)
       
  2664                   (Rules.prove ctxt strict (HOLogic.mk_Trueprop(USyntax.rhs(concl tc_eq)),
       
  2665                            terminator)))
       
  2666                  (r,ind)
       
  2667          handle Utils.ERR _ =>
       
  2668           (Rules.UNDISCH(Rules.MATCH_MP (Rules.MATCH_MP Thms.simp_thm r) tc_eq),
       
  2669            simplify_induction thy tc_eq ind))
       
  2670        end
       
  2671 
       
  2672    (*----------------------------------------------------------------------
       
  2673     * Nested termination conditions are harder to get at, since they are
       
  2674     * left embedded in the body of the function (and in induction
       
  2675     * theorem hypotheses). Our "solution" is to simplify them, and try to
       
  2676     * prove termination, but leave the application of the resulting theorem
       
  2677     * to a higher level. So things go much as in "simplify_tc": the
       
  2678     * termination condition (tc) is simplified to |- tc = tc' (there might
       
  2679     * not be a change) and then 2 attempts are made:
       
  2680     *
       
  2681     *   1. if |- tc = T, then return |- tc; otherwise,
       
  2682     *   2. apply the terminator to tc'. If |- tc' = T then return |- tc; else
       
  2683     *   3. return |- tc = tc'
       
  2684     *---------------------------------------------------------------------*)
       
  2685    fun simplify_nested_tc tc =
       
  2686       let val tc_eq = simplifier (tych (#2 (USyntax.strip_forall tc)))
       
  2687       in
       
  2688       Rules.GEN_ALL ctxt
       
  2689        (Rules.MATCH_MP Thms.eqT tc_eq
       
  2690         handle Utils.ERR _ =>
       
  2691           (Rules.MATCH_MP(Rules.MATCH_MP Thms.rev_eq_mp tc_eq)
       
  2692                       (Rules.prove ctxt strict (HOLogic.mk_Trueprop (USyntax.rhs(concl tc_eq)),
       
  2693                                terminator))
       
  2694             handle Utils.ERR _ => tc_eq))
       
  2695       end
       
  2696 
       
  2697    (*-------------------------------------------------------------------
       
  2698     * Attempt to simplify the termination conditions in each rule and
       
  2699     * in the induction theorem.
       
  2700     *-------------------------------------------------------------------*)
       
  2701    fun strip_imp tm = if USyntax.is_neg tm then ([],tm) else USyntax.strip_imp tm
       
  2702    fun loop ([],extras,R,ind) = (rev R, ind, extras)
       
  2703      | loop ((r,ftcs)::rst, nthms, R, ind) =
       
  2704         let val tcs = #1(strip_imp (concl r))
       
  2705             val extra_tcs = subtract (op aconv) tcs ftcs
       
  2706             val extra_tc_thms = map simplify_nested_tc extra_tcs
       
  2707             val (r1,ind1) = fold simplify_tc tcs (r,ind)
       
  2708             val r2 = Rules.FILTER_DISCH_ALL(not o USyntax.is_WFR) r1
       
  2709         in loop(rst, nthms@extra_tc_thms, r2::R, ind1)
       
  2710         end
       
  2711    val rules_tcs = ListPair.zip (Rules.CONJUNCTS rules1, TCs)
       
  2712    val (rules2,ind2,extras) = loop(rules_tcs,[],[],induction1)
       
  2713 in
       
  2714   {induction = ind2, rules = Rules.LIST_CONJ rules2, nested_tcs = extras}
       
  2715 end;
       
  2716 
       
  2717 end;
       
  2718 
       
  2719 
       
  2720 (*** second part of main module (postprocessing of TFL definitions) ***)
       
  2721 
       
  2722 structure Tfl: TFL =
       
  2723 struct
       
  2724 
       
  2725 (* misc *)
       
  2726 
       
  2727 (*---------------------------------------------------------------------------
       
  2728  * Extract termination goals so that they can be put it into a goalstack, or
       
  2729  * have a tactic directly applied to them.
       
  2730  *--------------------------------------------------------------------------*)
       
  2731 fun termination_goals rules =
       
  2732     map (Type.legacy_freeze o HOLogic.dest_Trueprop)
       
  2733       (fold_rev (union (op aconv) o Thm.prems_of) rules []);
       
  2734 
       
  2735 (*---------------------------------------------------------------------------
       
  2736  * Three postprocessors are applied to the definition.  It
       
  2737  * attempts to prove wellfoundedness of the given relation, simplifies the
       
  2738  * non-proved termination conditions, and finally attempts to prove the
       
  2739  * simplified termination conditions.
       
  2740  *--------------------------------------------------------------------------*)
       
  2741 fun std_postprocessor ctxt strict wfs =
       
  2742   Prim.postprocess ctxt strict
       
  2743    {wf_tac = REPEAT (ares_tac wfs 1),
       
  2744     terminator =
       
  2745       asm_simp_tac ctxt 1
       
  2746       THEN TRY (Arith_Data.arith_tac ctxt 1 ORELSE
       
  2747         fast_force_tac (ctxt addSDs @{thms not0_implies_Suc}) 1),
       
  2748     simplifier = Rules.simpl_conv ctxt []};
       
  2749 
       
  2750 
       
  2751 
       
  2752 val concl = #2 o Rules.dest_thm;
       
  2753 
       
  2754 (*---------------------------------------------------------------------------
       
  2755  * Postprocess a definition made by "define". This is a separate stage of
       
  2756  * processing from the definition stage.
       
  2757  *---------------------------------------------------------------------------*)
       
  2758 local
       
  2759 
       
  2760 (* The rest of these local definitions are for the tricky nested case *)
       
  2761 val solved = not o can USyntax.dest_eq o #2 o USyntax.strip_forall o concl
       
  2762 
       
  2763 fun id_thm th =
       
  2764    let val {lhs,rhs} = USyntax.dest_eq (#2 (USyntax.strip_forall (#2 (Rules.dest_thm th))));
       
  2765    in lhs aconv rhs end
       
  2766    handle Utils.ERR _ => false;
       
  2767 
       
  2768 val P_imp_P_eq_True = @{thm eqTrueI} RS eq_reflection;
       
  2769 fun mk_meta_eq r =
       
  2770   (case Thm.concl_of r of
       
  2771      Const(@{const_name Pure.eq},_)$_$_ => r
       
  2772   |   _ $(Const(@{const_name HOL.eq},_)$_$_) => r RS eq_reflection
       
  2773   |   _ => r RS P_imp_P_eq_True)
       
  2774 
       
  2775 (*Is this the best way to invoke the simplifier??*)
       
  2776 fun rewrite ctxt L = rewrite_rule ctxt (map mk_meta_eq (filter_out id_thm L))
       
  2777 
       
  2778 fun join_assums ctxt th =
       
  2779   let val tych = Thm.cterm_of ctxt
       
  2780       val {lhs,rhs} = USyntax.dest_eq(#2 (USyntax.strip_forall (concl th)))
       
  2781       val cntxtl = (#1 o USyntax.strip_imp) lhs  (* cntxtl should = cntxtr *)
       
  2782       val cntxtr = (#1 o USyntax.strip_imp) rhs  (* but union is solider *)
       
  2783       val cntxt = union (op aconv) cntxtl cntxtr
       
  2784   in
       
  2785     Rules.GEN_ALL ctxt
       
  2786       (Rules.DISCH_ALL
       
  2787          (rewrite ctxt (map (Rules.ASSUME o tych) cntxt) (Rules.SPEC_ALL th)))
       
  2788   end
       
  2789   val gen_all = USyntax.gen_all
       
  2790 in
       
  2791 fun proof_stage ctxt strict wfs {f, R, rules, full_pats_TCs, TCs} =
       
  2792   let
       
  2793     val _ = writeln "Proving induction theorem ..."
       
  2794     val ind =
       
  2795       Prim.mk_induction (Proof_Context.theory_of ctxt)
       
  2796         {fconst=f, R=R, SV=[], pat_TCs_list=full_pats_TCs}
       
  2797     val _ = writeln "Postprocessing ...";
       
  2798     val {rules, induction, nested_tcs} =
       
  2799       std_postprocessor ctxt strict wfs {rules=rules, induction=ind, TCs=TCs}
       
  2800   in
       
  2801   case nested_tcs
       
  2802   of [] => {induction=induction, rules=rules,tcs=[]}
       
  2803   | L  => let val dummy = writeln "Simplifying nested TCs ..."
       
  2804               val (solved,simplified,stubborn) =
       
  2805                fold_rev (fn th => fn (So,Si,St) =>
       
  2806                      if (id_thm th) then (So, Si, th::St) else
       
  2807                      if (solved th) then (th::So, Si, St)
       
  2808                      else (So, th::Si, St)) nested_tcs ([],[],[])
       
  2809               val simplified' = map (join_assums ctxt) simplified
       
  2810               val dummy = (Prim.trace_thms ctxt "solved =" solved;
       
  2811                            Prim.trace_thms ctxt "simplified' =" simplified')
       
  2812               val rewr = full_simplify (ctxt addsimps (solved @ simplified'));
       
  2813               val dummy = Prim.trace_thms ctxt "Simplifying the induction rule..." [induction]
       
  2814               val induction' = rewr induction
       
  2815               val dummy = Prim.trace_thms ctxt "Simplifying the recursion rules..." [rules]
       
  2816               val rules'     = rewr rules
       
  2817               val _ = writeln "... Postprocessing finished";
       
  2818           in
       
  2819           {induction = induction',
       
  2820                rules = rules',
       
  2821                  tcs = map (gen_all o USyntax.rhs o #2 o USyntax.strip_forall o concl)
       
  2822                            (simplified@stubborn)}
       
  2823           end
       
  2824   end;
       
  2825 
       
  2826 
       
  2827 (*lcp: curry the predicate of the induction rule*)
       
  2828 fun curry_rule ctxt rl =
       
  2829   Split_Rule.split_rule_var ctxt (Term.head_of (HOLogic.dest_Trueprop (Thm.concl_of rl))) rl;
       
  2830 
       
  2831 (*lcp: put a theorem into Isabelle form, using meta-level connectives*)
       
  2832 fun meta_outer ctxt =
       
  2833   curry_rule ctxt o Drule.export_without_context o
       
  2834   rule_by_tactic ctxt (REPEAT (FIRSTGOAL (resolve_tac ctxt [allI, impI, conjI] ORELSE' etac conjE)));
       
  2835 
       
  2836 (*Strip off the outer !P*)
       
  2837 val spec'=
       
  2838   Rule_Insts.read_instantiate @{context} [((("x", 0), Position.none), "P::'b=>bool")] [] spec;
       
  2839 
       
  2840 fun tracing true _ = ()
       
  2841   | tracing false msg = writeln msg;
       
  2842 
       
  2843 fun simplify_defn ctxt strict congs wfs id pats def0 =
       
  2844   let
       
  2845     val def = Thm.unvarify_global def0 RS meta_eq_to_obj_eq
       
  2846     val {rules, rows, TCs, full_pats_TCs} = Prim.post_definition ctxt congs (def, pats)
       
  2847     val {lhs=f,rhs} = USyntax.dest_eq (concl def)
       
  2848     val (_,[R,_]) = USyntax.strip_comb rhs
       
  2849     val dummy = Prim.trace_thms ctxt "congs =" congs
       
  2850     (*the next step has caused simplifier looping in some cases*)
       
  2851     val {induction, rules, tcs} =
       
  2852       proof_stage ctxt strict wfs
       
  2853        {f = f, R = R, rules = rules,
       
  2854         full_pats_TCs = full_pats_TCs,
       
  2855         TCs = TCs}
       
  2856     val rules' = map (Drule.export_without_context o Object_Logic.rulify_no_asm ctxt)
       
  2857                       (Rules.CONJUNCTS rules)
       
  2858   in
       
  2859     {induct = meta_outer ctxt (Object_Logic.rulify_no_asm ctxt (induction RS spec')),
       
  2860      rules = ListPair.zip(rules', rows),
       
  2861      tcs = (termination_goals rules') @ tcs}
       
  2862   end
       
  2863   handle Utils.ERR {mesg,func,module} =>
       
  2864     error (mesg ^ "\n    (In TFL function " ^ module ^ "." ^ func ^ ")");
       
  2865 
       
  2866 
       
  2867 (* Derive the initial equations from the case-split rules to meet the
       
  2868 users specification of the recursive function. *)
       
  2869 local
       
  2870   fun get_related_thms i =
       
  2871       map_filter ((fn (r,x) => if x = i then SOME r else NONE));
       
  2872 
       
  2873   fun solve_eq _ (th, [], i) =  error "derive_init_eqs: missing rules"
       
  2874     | solve_eq _ (th, [a], i) = [(a, i)]
       
  2875     | solve_eq ctxt (th, splitths, i) =
       
  2876       (writeln "Proving unsplit equation...";
       
  2877       [((Drule.export_without_context o Object_Logic.rulify_no_asm ctxt)
       
  2878           (CaseSplit.splitto ctxt splitths th), i)])
       
  2879       handle ERROR s =>
       
  2880              (warning ("recdef (solve_eq): " ^ s); map (fn x => (x,i)) splitths);
       
  2881 in
       
  2882 fun derive_init_eqs ctxt rules eqs =
       
  2883   map (Thm.trivial o Thm.cterm_of ctxt o HOLogic.mk_Trueprop) eqs
       
  2884   |> map_index (fn (i, e) => solve_eq ctxt (e, (get_related_thms i rules), i))
       
  2885   |> flat;
       
  2886 end;
       
  2887 
       
  2888 
       
  2889 (*---------------------------------------------------------------------------
       
  2890  * Defining a function with an associated termination relation.
       
  2891  *---------------------------------------------------------------------------*)
       
  2892 fun define_i strict congs wfs fid R eqs ctxt =
       
  2893   let
       
  2894     val thy = Proof_Context.theory_of ctxt
       
  2895     val {functional, pats} = Prim.mk_functional thy eqs
       
  2896     val (def, thy') = Prim.wfrec_definition0 fid R functional thy
       
  2897     val ctxt' = Proof_Context.transfer thy' ctxt
       
  2898     val (lhs, _) = Logic.dest_equals (Thm.prop_of def)
       
  2899     val {induct, rules, tcs} = simplify_defn ctxt' strict congs wfs fid pats def
       
  2900     val rules' = if strict then derive_init_eqs ctxt' rules eqs else rules
       
  2901   in ({lhs = lhs, rules = rules', induct = induct, tcs = tcs}, ctxt') end;
       
  2902 
       
  2903 fun define strict congs wfs fid R seqs ctxt =
       
  2904   define_i strict congs wfs fid
       
  2905     (Syntax.read_term ctxt R) (map (Syntax.read_term ctxt) seqs) ctxt
       
  2906       handle Utils.ERR {mesg,...} => error mesg;
       
  2907 
       
  2908 
       
  2909 (*---------------------------------------------------------------------------
       
  2910  *
       
  2911  *     Definitions with synthesized termination relation
       
  2912  *
       
  2913  *---------------------------------------------------------------------------*)
       
  2914 
       
  2915 fun func_of_cond_eqn tm =
       
  2916   #1 (USyntax.strip_comb (#lhs (USyntax.dest_eq (#2 (USyntax.strip_forall (#2 (USyntax.strip_imp tm)))))));
       
  2917 
       
  2918 fun defer_i congs fid eqs thy =
       
  2919  let
       
  2920      val {rules,R,theory,full_pats_TCs,SV,...} = Prim.lazyR_def thy fid congs eqs
       
  2921      val f = func_of_cond_eqn (concl (Rules.CONJUNCT1 rules handle Utils.ERR _ => rules));
       
  2922      val dummy = writeln "Proving induction theorem ...";
       
  2923      val induction = Prim.mk_induction theory
       
  2924                         {fconst=f, R=R, SV=SV, pat_TCs_list=full_pats_TCs}
       
  2925  in
       
  2926    (*return the conjoined induction rule and recursion equations,
       
  2927      with assumptions remaining to discharge*)
       
  2928    (Drule.export_without_context (induction RS (rules RS conjI)), theory)
       
  2929  end
       
  2930 
       
  2931 fun defer congs fid seqs thy =
       
  2932   defer_i congs fid (map (Syntax.read_term_global thy) seqs) thy
       
  2933     handle Utils.ERR {mesg,...} => error mesg;
       
  2934 end;
       
  2935 
       
  2936 end;
       
  2937 
       
  2938 
       
  2939 (*** wrappers for Isar ***)
       
  2940 
       
  2941 (** recdef hints **)
       
  2942 
       
  2943 (* type hints *)
       
  2944 
       
  2945 type hints = {simps: thm list, congs: (string * thm) list, wfs: thm list};
       
  2946 
       
  2947 fun mk_hints (simps, congs, wfs) = {simps = simps, congs = congs, wfs = wfs}: hints;
       
  2948 fun map_hints f ({simps, congs, wfs}: hints) = mk_hints (f (simps, congs, wfs));
       
  2949 
       
  2950 fun map_simps f = map_hints (fn (simps, congs, wfs) => (f simps, congs, wfs));
       
  2951 fun map_congs f = map_hints (fn (simps, congs, wfs) => (simps, f congs, wfs));
       
  2952 fun map_wfs f = map_hints (fn (simps, congs, wfs) => (simps, congs, f wfs));
       
  2953 
       
  2954 
       
  2955 (* congruence rules *)
       
  2956 
       
  2957 local
       
  2958 
       
  2959 val cong_head =
       
  2960   fst o Term.dest_Const o Term.head_of o fst o Logic.dest_equals o Thm.concl_of;
       
  2961 
       
  2962 fun prep_cong raw_thm =
       
  2963   let val thm = safe_mk_meta_eq raw_thm in (cong_head thm, thm) end;
       
  2964 
       
  2965 in
       
  2966 
       
  2967 fun add_cong raw_thm congs =
       
  2968   let
       
  2969     val (c, thm) = prep_cong raw_thm;
       
  2970     val _ = if AList.defined (op =) congs c
       
  2971       then warning ("Overwriting recdef congruence rule for " ^ quote c)
       
  2972       else ();
       
  2973   in AList.update (op =) (c, thm) congs end;
       
  2974 
       
  2975 fun del_cong raw_thm congs =
       
  2976   let
       
  2977     val (c, thm) = prep_cong raw_thm;
       
  2978     val _ = if AList.defined (op =) congs c
       
  2979       then ()
       
  2980       else warning ("No recdef congruence rule for " ^ quote c);
       
  2981   in AList.delete (op =) c congs end;
       
  2982 
       
  2983 end;
       
  2984 
       
  2985 
       
  2986 
       
  2987 (** global and local recdef data **)
       
  2988 
       
  2989 (* theory data *)
       
  2990 
       
  2991 type recdef_info = {lhs: term, simps: thm list, rules: thm list list, induct: thm, tcs: term list};
       
  2992 
       
  2993 structure Data = Generic_Data
       
  2994 (
       
  2995   type T = recdef_info Symtab.table * hints;
       
  2996   val empty = (Symtab.empty, mk_hints ([], [], [])): T;
       
  2997   val extend = I;
       
  2998   fun merge
       
  2999    ((tab1, {simps = simps1, congs = congs1, wfs = wfs1}),
       
  3000     (tab2, {simps = simps2, congs = congs2, wfs = wfs2})) : T =
       
  3001       (Symtab.merge (K true) (tab1, tab2),
       
  3002         mk_hints (Thm.merge_thms (simps1, simps2),
       
  3003           AList.merge (op =) (K true) (congs1, congs2),
       
  3004           Thm.merge_thms (wfs1, wfs2)));
       
  3005 );
       
  3006 
       
  3007 val get_recdef = Symtab.lookup o #1 o Data.get o Context.Theory;
       
  3008 
       
  3009 fun put_recdef name info =
       
  3010   (Context.theory_map o Data.map o apfst) (fn tab =>
       
  3011     Symtab.update_new (name, info) tab
       
  3012       handle Symtab.DUP _ => error ("Duplicate recursive function definition " ^ quote name));
       
  3013 
       
  3014 val get_hints = #2 o Data.get o Context.Proof;
       
  3015 val map_hints = Data.map o apsnd;
       
  3016 
       
  3017 
       
  3018 (* attributes *)
       
  3019 
       
  3020 fun attrib f = Thm.declaration_attribute (map_hints o f);
       
  3021 
       
  3022 val simp_add = attrib (map_simps o Thm.add_thm);
       
  3023 val simp_del = attrib (map_simps o Thm.del_thm);
       
  3024 val cong_add = attrib (map_congs o add_cong);
       
  3025 val cong_del = attrib (map_congs o del_cong);
       
  3026 val wf_add = attrib (map_wfs o Thm.add_thm);
       
  3027 val wf_del = attrib (map_wfs o Thm.del_thm);
       
  3028 
       
  3029 
       
  3030 (* modifiers *)
       
  3031 
       
  3032 val recdef_simpN = "recdef_simp";
       
  3033 val recdef_congN = "recdef_cong";
       
  3034 val recdef_wfN = "recdef_wf";
       
  3035 
       
  3036 val recdef_modifiers =
       
  3037  [Args.$$$ recdef_simpN -- Args.colon >> K (Method.modifier simp_add @{here}),
       
  3038   Args.$$$ recdef_simpN -- Args.add -- Args.colon >> K (Method.modifier simp_add @{here}),
       
  3039   Args.$$$ recdef_simpN -- Args.del -- Args.colon >> K (Method.modifier simp_del @{here}),
       
  3040   Args.$$$ recdef_congN -- Args.colon >> K (Method.modifier cong_add @{here}),
       
  3041   Args.$$$ recdef_congN -- Args.add -- Args.colon >> K (Method.modifier cong_add @{here}),
       
  3042   Args.$$$ recdef_congN -- Args.del -- Args.colon >> K (Method.modifier cong_del @{here}),
       
  3043   Args.$$$ recdef_wfN -- Args.colon >> K (Method.modifier wf_add @{here}),
       
  3044   Args.$$$ recdef_wfN -- Args.add -- Args.colon >> K (Method.modifier wf_add @{here}),
       
  3045   Args.$$$ recdef_wfN -- Args.del -- Args.colon >> K (Method.modifier wf_del @{here})] @
       
  3046   Clasimp.clasimp_modifiers;
       
  3047 
       
  3048 
       
  3049 
       
  3050 (** prepare hints **)
       
  3051 
       
  3052 fun prepare_hints opt_src ctxt =
       
  3053   let
       
  3054     val ctxt' =
       
  3055       (case opt_src of
       
  3056         NONE => ctxt
       
  3057       | SOME src => #2 (Token.syntax (Method.sections recdef_modifiers) src ctxt));
       
  3058     val {simps, congs, wfs} = get_hints ctxt';
       
  3059     val ctxt'' = ctxt' addsimps simps |> Simplifier.del_cong @{thm imp_cong};
       
  3060   in ((rev (map snd congs), wfs), ctxt'') end;
       
  3061 
       
  3062 fun prepare_hints_i () ctxt =
       
  3063   let
       
  3064     val {simps, congs, wfs} = get_hints ctxt;
       
  3065     val ctxt' = ctxt addsimps simps |> Simplifier.del_cong @{thm imp_cong};
       
  3066   in ((rev (map snd congs), wfs), ctxt') end;
       
  3067 
       
  3068 
       
  3069 
       
  3070 (** add_recdef(_i) **)
       
  3071 
       
  3072 fun gen_add_recdef tfl_fn prep_att prep_hints not_permissive raw_name R eq_srcs hints thy =
       
  3073   let
       
  3074     val _ = legacy_feature "Old 'recdef' command -- use 'fun' or 'function' instead";
       
  3075 
       
  3076     val name = Sign.intern_const thy raw_name;
       
  3077     val bname = Long_Name.base_name name;
       
  3078     val _ = writeln ("Defining recursive function " ^ quote name ^ " ...");
       
  3079 
       
  3080     val ((eq_names, eqs), raw_eq_atts) = apfst split_list (split_list eq_srcs);
       
  3081     val eq_atts = map (map (prep_att thy)) raw_eq_atts;
       
  3082 
       
  3083     val ((congs, wfs), ctxt) = prep_hints hints (Proof_Context.init_global thy);
       
  3084     (*We must remove imp_cong to prevent looping when the induction rule
       
  3085       is simplified. Many induction rules have nested implications that would
       
  3086       give rise to looping conditional rewriting.*)
       
  3087     val ({lhs, rules = rules_idx, induct, tcs}, ctxt1) =
       
  3088       tfl_fn not_permissive congs wfs name R eqs ctxt;
       
  3089     val rules = (map o map) fst (partition_eq (eq_snd (op = : int * int -> bool)) rules_idx);
       
  3090     val simp_att =
       
  3091       if null tcs then [Simplifier.simp_add,
       
  3092         Named_Theorems.add @{named_theorems nitpick_simp}, Code.add_default_eqn_attribute]
       
  3093       else [];
       
  3094     val ((simps' :: rules', [induct']), thy2) =
       
  3095       Proof_Context.theory_of ctxt1
       
  3096       |> Sign.add_path bname
       
  3097       |> Global_Theory.add_thmss
       
  3098         (((Binding.name "simps", flat rules), simp_att) :: ((eq_names ~~ rules) ~~ eq_atts))
       
  3099       ||>> Global_Theory.add_thms [((Binding.name "induct", induct), [])]
       
  3100       ||> Spec_Rules.add_global Spec_Rules.Equational ([lhs], flat rules);
       
  3101     val result = {lhs = lhs, simps = simps', rules = rules', induct = induct', tcs = tcs};
       
  3102     val thy3 =
       
  3103       thy2
       
  3104       |> put_recdef name result
       
  3105       |> Sign.parent_path;
       
  3106   in (thy3, result) end;
       
  3107 
       
  3108 val add_recdef = gen_add_recdef Tfl.define Attrib.attribute_cmd_global prepare_hints;
       
  3109 fun add_recdef_i x y z w = gen_add_recdef Tfl.define_i (K I) prepare_hints_i x y z w ();
       
  3110 
       
  3111 
       
  3112 
       
  3113 (** defer_recdef(_i) **)
       
  3114 
       
  3115 fun gen_defer_recdef tfl_fn eval_thms raw_name eqs raw_congs thy =
       
  3116   let
       
  3117     val name = Sign.intern_const thy raw_name;
       
  3118     val bname = Long_Name.base_name name;
       
  3119 
       
  3120     val _ = writeln ("Deferred recursive function " ^ quote name ^ " ...");
       
  3121 
       
  3122     val congs = eval_thms (Proof_Context.init_global thy) raw_congs;
       
  3123     val (induct_rules, thy2) = tfl_fn congs name eqs thy;
       
  3124     val ([induct_rules'], thy3) =
       
  3125       thy2
       
  3126       |> Sign.add_path bname
       
  3127       |> Global_Theory.add_thms [((Binding.name "induct_rules", induct_rules), [])]
       
  3128       ||> Sign.parent_path;
       
  3129   in (thy3, {induct_rules = induct_rules'}) end;
       
  3130 
       
  3131 val defer_recdef = gen_defer_recdef Tfl.defer Attrib.eval_thms;
       
  3132 val defer_recdef_i = gen_defer_recdef Tfl.defer_i (K I);
       
  3133 
       
  3134 
       
  3135 
       
  3136 (** recdef_tc(_i) **)
       
  3137 
       
  3138 fun gen_recdef_tc prep_att prep_name (bname, raw_atts) raw_name opt_i int lthy =
       
  3139   let
       
  3140     val thy = Proof_Context.theory_of lthy;
       
  3141     val name = prep_name thy raw_name;
       
  3142     val atts = map (prep_att lthy) raw_atts;
       
  3143     val tcs =
       
  3144       (case get_recdef thy name of
       
  3145         NONE => error ("No recdef definition of constant: " ^ quote name)
       
  3146       | SOME {tcs, ...} => tcs);
       
  3147     val i = the_default 1 opt_i;
       
  3148     val tc = nth tcs (i - 1) handle General.Subscript =>
       
  3149       error ("No termination condition #" ^ string_of_int i ^
       
  3150         " in recdef definition of " ^ quote name);
       
  3151   in
       
  3152     Specification.theorem "" NONE (K I)
       
  3153       (Binding.concealed (Binding.name bname), atts) [] []
       
  3154       (Element.Shows [(Attrib.empty_binding, [(HOLogic.mk_Trueprop tc, [])])]) int lthy
       
  3155   end;
       
  3156 
       
  3157 val recdef_tc = gen_recdef_tc Attrib.check_src Sign.intern_const;
       
  3158 val recdef_tc_i = gen_recdef_tc (K I) (K I);
       
  3159 
       
  3160 
       
  3161 
       
  3162 (** package setup **)
       
  3163 
       
  3164 (* setup theory *)
       
  3165 
       
  3166 val _ =
       
  3167   Theory.setup
       
  3168    (Attrib.setup @{binding recdef_simp} (Attrib.add_del simp_add simp_del)
       
  3169       "declaration of recdef simp rule" #>
       
  3170     Attrib.setup @{binding recdef_cong} (Attrib.add_del cong_add cong_del)
       
  3171       "declaration of recdef cong rule" #>
       
  3172     Attrib.setup @{binding recdef_wf} (Attrib.add_del wf_add wf_del)
       
  3173       "declaration of recdef wf rule");
       
  3174 
       
  3175 
       
  3176 (* outer syntax *)
       
  3177 
       
  3178 val hints =
       
  3179   @{keyword "("} |--
       
  3180     Parse.!!! (Parse.position @{keyword "hints"} -- Parse.args --| @{keyword ")"})
       
  3181   >> uncurry Token.src;
       
  3182 
       
  3183 val recdef_decl =
       
  3184   Scan.optional
       
  3185     (@{keyword "("} -- Parse.!!! (@{keyword "permissive"} -- @{keyword ")"}) >> K false) true --
       
  3186   Parse.name -- Parse.term -- Scan.repeat1 (Parse_Spec.opt_thm_name ":" -- Parse.prop)
       
  3187     -- Scan.option hints
       
  3188   >> (fn ((((p, f), R), eqs), src) => #1 o add_recdef p f R (map Parse.triple_swap eqs) src);
       
  3189 
       
  3190 val _ =
       
  3191   Outer_Syntax.command @{command_keyword recdef} "define general recursive functions (obsolete TFL)"
       
  3192     (recdef_decl >> Toplevel.theory);
       
  3193 
       
  3194 
       
  3195 val defer_recdef_decl =
       
  3196   Parse.name -- Scan.repeat1 Parse.prop --
       
  3197   Scan.optional
       
  3198     (@{keyword "("} |-- @{keyword "congs"} |-- Parse.!!! (Parse.xthms1 --| @{keyword ")"})) []
       
  3199   >> (fn ((f, eqs), congs) => #1 o defer_recdef f eqs congs);
       
  3200 
       
  3201 val _ =
       
  3202   Outer_Syntax.command @{command_keyword defer_recdef}
       
  3203     "defer general recursive functions (obsolete TFL)"
       
  3204     (defer_recdef_decl >> Toplevel.theory);
       
  3205 
       
  3206 val _ =
       
  3207   Outer_Syntax.local_theory_to_proof' @{command_keyword recdef_tc}
       
  3208     "recommence proof of termination condition (obsolete TFL)"
       
  3209     ((Parse_Spec.opt_thm_name ":" >> apfst Binding.name_of) -- Parse.xname --
       
  3210         Scan.option (@{keyword "("} |-- Parse.nat --| @{keyword ")"})
       
  3211       >> (fn ((thm_name, name), i) => recdef_tc thm_name name i));
       
  3212 
       
  3213 end;