src/Provers/induct_method.ML
changeset 18147 31634a2af39e
parent 18023 3900037edf3d
child 18178 9e4dfe031525
equal deleted inserted replaced
18146:47463b1825c6 18147:31634a2af39e
    20 signature INDUCT_METHOD =
    20 signature INDUCT_METHOD =
    21 sig
    21 sig
    22   val cases_tac: Proof.context -> bool -> term option list list -> thm option ->
    22   val cases_tac: Proof.context -> bool -> term option list list -> thm option ->
    23     thm list -> int -> RuleCases.tactic
    23     thm list -> int -> RuleCases.tactic
    24   val induct_tac: Proof.context -> bool -> term option list list ->
    24   val induct_tac: Proof.context -> bool -> term option list list ->
    25     thm option -> thm list -> int -> RuleCases.tactic
    25     thm option -> (string * typ) list -> thm list -> int -> RuleCases.tactic
    26   val setup: (theory -> theory) list
    26   val setup: (theory -> theory) list
    27 end;
    27 end;
    28 
    28 
    29 functor InductMethodFun(Data: INDUCT_METHOD_DATA): INDUCT_METHOD =
    29 functor InductMethodFun(Data: INDUCT_METHOD_DATA): INDUCT_METHOD =
    30 struct
    30 struct
    48 fun prep_inst align cert tune (tm, ts) =
    48 fun prep_inst align cert tune (tm, ts) =
    49   let
    49   let
    50     fun prep_var (x, SOME t) =
    50     fun prep_var (x, SOME t) =
    51           let
    51           let
    52             val cx = cert x;
    52             val cx = cert x;
    53             val {T = xT, sign, ...} = Thm.rep_cterm cx;
    53             val {T = xT, thy, ...} = Thm.rep_cterm cx;
    54             val ct = cert (tune t);
    54             val ct = cert (tune t);
    55           in
    55           in
    56             if Sign.typ_instance sign (#T (Thm.rep_cterm ct), xT) then SOME (cx, ct)
    56             if Sign.typ_instance thy (#T (Thm.rep_cterm ct), xT) then SOME (cx, ct)
    57             else raise ERROR_MESSAGE (Pretty.string_of (Pretty.block
    57             else raise ERROR_MESSAGE (Pretty.string_of (Pretty.block
    58              [Pretty.str "Ill-typed instantiation:", Pretty.fbrk,
    58              [Pretty.str "Ill-typed instantiation:", Pretty.fbrk,
    59               Display.pretty_cterm ct, Pretty.str " ::", Pretty.brk 1,
    59               Display.pretty_cterm ct, Pretty.str " ::", Pretty.brk 1,
    60               Display.pretty_ctyp (#T (Thm.crep_cterm ct))]))
    60               Display.pretty_ctyp (#T (Thm.crep_cterm ct))]))
    61           end
    61           end
    79 *)
    79 *)
    80 
    80 
    81 local
    81 local
    82 
    82 
    83 fun resolveq_cases_tac make ruleq i st =
    83 fun resolveq_cases_tac make ruleq i st =
    84   ruleq |> Seq.map (fn (rule, (cases, facts)) =>
    84   ruleq |> Seq.maps (fn (rule, (cases, facts)) =>
    85     (Method.insert_tac facts THEN' Tactic.rtac rule) i st
    85     (Method.insert_tac facts THEN' Tactic.rtac rule) i st
    86     |> Seq.map (rpair (make (Thm.sign_of_thm rule, Thm.prop_of rule) cases)))
    86     |> Seq.map (rpair (make (Thm.theory_of_thm rule, Thm.prop_of rule) cases)));
    87   |> Seq.flat;
       
    88 
    87 
    89 fun find_casesT ctxt ((SOME t :: _) :: _) = InductAttrib.find_casesT ctxt (fastype_of t)
    88 fun find_casesT ctxt ((SOME t :: _) :: _) = InductAttrib.find_casesT ctxt (fastype_of t)
    90   | find_casesT _ _ = [];
    89   | find_casesT _ _ = [];
    91 
    90 
    92 fun find_casesS ctxt (fact :: _) = InductAttrib.find_casesS ctxt fact
    91 fun find_casesS ctxt (fact :: _) = InductAttrib.find_casesS ctxt fact
    94 
    93 
    95 in
    94 in
    96 
    95 
    97 fun cases_tac ctxt is_open insts opt_rule facts =
    96 fun cases_tac ctxt is_open insts opt_rule facts =
    98   let
    97   let
    99     val sg = ProofContext.sign_of ctxt;
    98     val thy = ProofContext.theory_of ctxt;
   100     val cert = Thm.cterm_of sg;
    99     val cert = Thm.cterm_of thy;
   101 
   100 
   102     fun inst_rule r =
   101     fun inst_rule r =
   103       if null insts then RuleCases.add r
   102       if null insts then RuleCases.add r
   104       else (align_left "Rule has fewer premises than arguments given" (Thm.prems_of r) insts
   103       else (align_left "Rule has fewer premises than arguments given" (Thm.prems_of r) insts
   105         |> (List.concat o map (prep_inst align_left cert I))
   104         |> (List.concat o map (prep_inst align_left cert I))
   108     val ruleq =
   107     val ruleq =
   109       (case opt_rule of
   108       (case opt_rule of
   110         NONE =>
   109         NONE =>
   111           let val rules = find_casesS ctxt facts @ find_casesT ctxt insts @ [Data.cases_default] in
   110           let val rules = find_casesS ctxt facts @ find_casesT ctxt insts @ [Data.cases_default] in
   112             Method.trace ctxt rules;
   111             Method.trace ctxt rules;
   113             Seq.flat (Seq.map (Seq.try inst_rule) (Seq.of_list rules))
   112             Seq.maps (Seq.try inst_rule) (Seq.of_list rules)
   114           end
   113           end
   115       | SOME r => Seq.single (inst_rule r));
   114       | SOME r => Seq.single (inst_rule r));
   116 
   115 
   117     fun prep_rule (th, (cases, n)) = Seq.map (apsnd (rpair (Library.drop (n, facts))) o rpair cases)
   116     fun prep_rule (th, (cases, n)) = Seq.map (apsnd (rpair (Library.drop (n, facts))) o rpair cases)
   118       (Method.multi_resolves (Library.take (n, facts)) [th]);
   117       (Method.multi_resolves (Library.take (n, facts)) [th]);
   119   in resolveq_cases_tac (RuleCases.make is_open NONE) (Seq.flat (Seq.map prep_rule ruleq)) end;
   118   in resolveq_cases_tac (RuleCases.make is_open NONE) (Seq.maps prep_rule ruleq) end;
   120 
   119 
   121 val cases_meth = Method.METHOD_CASES o ((Seq.DETERM o HEADGOAL) oo
   120 val cases_meth = Method.METHOD_CASES o ((Seq.DETERM o HEADGOAL) oo
   122   (fn (ctxt, (is_open, (insts, opt_rule))) => cases_tac ctxt is_open insts opt_rule));
   121   (fn (ctxt, (is_open, (insts, opt_rule))) => cases_tac ctxt is_open insts opt_rule));
   123 
   122 
   124 end;
   123 end;
   137 local
   136 local
   138 
   137 
   139 
   138 
   140 (* atomize and rulify *)
   139 (* atomize and rulify *)
   141 
   140 
   142 fun atomize_term sg =
   141 fun atomize_term thy =
   143   ObjectLogic.drop_judgment sg o MetaSimplifier.rewrite_term sg Data.atomize [];
   142   ObjectLogic.drop_judgment thy o MetaSimplifier.rewrite_term thy Data.atomize [];
   144 
   143 
   145 fun rulified_term thm =
   144 fun rulified_term thm =
   146   let val sg = Thm.sign_of_thm thm in
   145   let val thy = Thm.theory_of_thm thm in
   147     Thm.prop_of thm
   146     Thm.prop_of thm
   148     |> MetaSimplifier.rewrite_term sg Data.rulify1 []
   147     |> MetaSimplifier.rewrite_term thy Data.rulify1 []
   149     |> MetaSimplifier.rewrite_term sg Data.rulify2 []
   148     |> MetaSimplifier.rewrite_term thy Data.rulify2 []
   150     |> pair sg
   149     |> pair thy
   151   end;
   150   end;
   152 
   151 
   153 val atomize_tac = Tactic.rewrite_goal_tac Data.atomize;
   152 val atomize_tac = Tactic.rewrite_goal_tac Data.atomize;
   154 
   153 
   155 val rulify_tac =
   154 val rulify_tac =
   158   Tactic.norm_hhf_tac;
   157   Tactic.norm_hhf_tac;
   159 
   158 
   160 val localize = Goal.norm_hhf o Tactic.simplify false Data.localize;
   159 val localize = Goal.norm_hhf o Tactic.simplify false Data.localize;
   161 
   160 
   162 
   161 
   163 (* imp_intr --- limited to atomic prems *)
   162 (* fix_tac *)
       
   163 
       
   164 local
       
   165 
       
   166 val meta_spec = PureThy.get_thm Pure.thy (Name "meta_spec");
       
   167 
       
   168 fun meta_spec_tac ctxt (x, T) i st = SUBGOAL (fn (goal, _) =>
       
   169   let
       
   170     val thy = Thm.theory_of_thm st;
       
   171     val cert = Thm.cterm_of thy;
       
   172     val certT = Thm.ctyp_of thy;
       
   173 
       
   174     val v = Free (x, T);
       
   175     val _ = Term.exists_subterm (fn t => t aconv v) goal orelse
       
   176       error ("No occurrence of " ^ ProofContext.string_of_term ctxt v ^ " in subgoal");
       
   177     val P = Term.absfree (x, T, goal);
       
   178     val rule = meta_spec
       
   179       |> Drule.instantiate' [SOME (certT T)] [SOME (cert P), SOME (cert v)]
       
   180       |> Thm.rename_params_rule ([x], 1);
       
   181   in compose_tac (false, rule, 1) end i) i st;
       
   182 
       
   183 in
       
   184 
       
   185 fun fix_tac ctxt fixes = EVERY' (map (meta_spec_tac ctxt) (rev fixes));
       
   186 
       
   187 end;
       
   188 
       
   189 
       
   190 (* internalize implications -- limited to atomic prems *)
       
   191 
       
   192 local
   164 
   193 
   165 fun imp_intr i raw_th =
   194 fun imp_intr i raw_th =
   166   let
   195   let
   167     val th = Thm.permute_prems (i - 1) 1 raw_th;
   196     val th = Thm.permute_prems (i - 1) 1 raw_th;
       
   197     val {thy, maxidx, ...} = Thm.rep_thm th;
   168     val cprems = Drule.cprems_of th;
   198     val cprems = Drule.cprems_of th;
   169     val As = Library.take (length cprems - 1, cprems);
   199     val As = Library.take (length cprems - 1, cprems);
   170     val C = Thm.cterm_of (Thm.sign_of_thm th) (Var (("C", #maxidx (Thm.rep_thm th) + 1), propT));
   200     val C = Thm.cterm_of thy (Var (("C", maxidx + 1), propT));
   171   in th COMP Thm.lift_rule (Drule.list_implies (As, C)) Data.local_impI end;
   201   in th COMP Thm.lift_rule (Drule.list_implies (As, C)) Data.local_impI end;
       
   202 
       
   203 in
       
   204 
       
   205 fun internalize k th = if k > 0 then internalize (k - 1) (imp_intr k th) else th;
       
   206 
       
   207 end;
   172 
   208 
   173 
   209 
   174 (* join multi-rules *)
   210 (* join multi-rules *)
   175 
   211 
   176 val eq_prems = curry (Term.aconvs o pairself Thm.prems_of);
   212 val eq_prems = curry (Term.aconvs o pairself Thm.prems_of);
   193         end;
   229         end;
   194 
   230 
   195 
   231 
   196 (* divinate rule instantiation (cannot handle pending goal parameters) *)
   232 (* divinate rule instantiation (cannot handle pending goal parameters) *)
   197 
   233 
   198 fun dest_env sign (env as Envir.Envir {iTs, ...}) =
   234 fun dest_env thy (env as Envir.Envir {iTs, ...}) =
   199   let
   235   let
       
   236     val cert = Thm.cterm_of thy;
       
   237     val certT = Thm.ctyp_of thy;
   200     val pairs = Envir.alist_of env;
   238     val pairs = Envir.alist_of env;
   201     val ts = map (Thm.cterm_of sign o Envir.norm_term env o #2 o #2) pairs;
   239     val ts = map (cert o Envir.norm_term env o #2 o #2) pairs;
   202     val xs = map2 (Thm.cterm_of sign o Var) (map #1 pairs, map (#T o Thm.rep_cterm) ts);
   240     val xs = map2 (cert o Var) (map #1 pairs, map (#T o Thm.rep_cterm) ts);
   203     val cert = Thm.ctyp_of sign;
   241   in (map (fn (xi, (S, T)) => (certT (TVar (xi, S)), certT T)) (Vartab.dest iTs), xs ~~ ts) end;
   204   in (map (fn (ixn, (S, T)) => (cert (TVar (ixn, S)), cert T)) (Vartab.dest iTs), xs ~~ ts) end;
       
   205 
   242 
   206 fun divinate_inst rule i st =
   243 fun divinate_inst rule i st =
   207   let
   244   let
   208     val {sign, maxidx, ...} = Thm.rep_thm st;
   245     val {thy, maxidx, ...} = Thm.rep_thm st;
   209     val goal = List.nth (Thm.prems_of st, i - 1);  (*exception Subscript*)
   246     val goal = Thm.term_of (Thm.cprem_of st i);  (*exception Subscript*)
   210     val params = rev (rename_wrt_term goal (Logic.strip_params goal));  (*as they are printed :-*)
   247     val params = rev (rename_wrt_term goal (Logic.strip_params goal));  (*as they are printed :-*)
   211   in
   248   in
   212     if not (null params) then
   249     if not (null params) then
   213       (warning ("Cannot determine rule instantiation due to pending parameter(s): " ^
   250       (warning ("Cannot determine rule instantiation due to pending parameter(s): " ^
   214         commas (map (Sign.string_of_term sign o Syntax.mark_boundT) params));
   251         commas (map (Sign.string_of_term thy o Syntax.mark_boundT) params));
   215       Seq.single rule)
   252       Seq.single rule)
   216     else
   253     else
   217       let
   254       let
   218         val rule' = Thm.incr_indexes (maxidx + 1) rule;
   255         val rule' = Thm.incr_indexes (maxidx + 1) rule;
   219         val concl = Logic.strip_assums_concl goal;
   256         val concl = Logic.strip_assums_concl goal;
   220       in
   257       in
   221         Unify.smash_unifiers (sign, Envir.empty (#maxidx (Thm.rep_thm rule')),
   258         Unify.smash_unifiers (thy, Envir.empty (#maxidx (Thm.rep_thm rule')),
   222           [(Thm.concl_of rule', concl)])
   259           [(Thm.concl_of rule', concl)])
   223         |> Seq.map (fn env => Drule.instantiate (dest_env sign env) rule')
   260         |> Seq.map (fn env => Drule.instantiate (dest_env thy env) rule')
   224       end
   261       end
   225   end handle Subscript => Seq.empty;
   262   end handle Subscript => Seq.empty;
   226 
   263 
   227 
   264 
   228 (* compose tactics with cases *)
   265 (* compose tactics with cases *)
   229 
   266 
   230 fun internalize k th = if k > 0 then internalize (k - 1) (imp_intr k th) else th;
   267 fun resolveq_cases_tac' ctxt make is_open ruleq fixes i st =
   231 
   268   ruleq |> Seq.maps (fn (rule, (cases, k, more_facts)) =>
   232 fun resolveq_cases_tac' make is_open ruleq i st =
   269     (Method.insert_tac more_facts THEN' fix_tac ctxt fixes THEN' atomize_tac) i st
   233   ruleq |> Seq.map (fn (rule, (cases, k, more_facts)) => st
   270     |> Seq.maps (fn st' =>
   234     |> (Method.insert_tac more_facts THEN' atomize_tac) i
   271       divinate_inst (internalize k rule) i st'
   235     |> Seq.map (fn st' => divinate_inst (internalize k rule) i st' |> Seq.map (fn rule' =>
   272       |> Seq.maps (fn rule' =>
   236           st' |> Tactic.rtac rule' i
   273         Tactic.rtac rule' i st'
   237           |> Seq.map (rpair (make is_open (SOME (Thm.prop_of rule')) (rulified_term rule') cases)))
   274         |> Seq.map (rpair (make is_open (SOME (Thm.prop_of rule')) (rulified_term rule') cases)))));
   238       |> Seq.flat)
       
   239     |> Seq.flat)
       
   240   |> Seq.flat;
       
   241 
   275 
   242 infix 1 THEN_ALL_NEW_CASES;
   276 infix 1 THEN_ALL_NEW_CASES;
   243 
   277 
   244 fun (tac1 THEN_ALL_NEW_CASES tac2) i st =
   278 fun (tac1 THEN_ALL_NEW_CASES tac2) i st =
   245   st |> Seq.THEN (tac1 i, (fn (st', cases) =>
   279   st |> tac1 i |> Seq.maps (fn (st', cases) =>
   246     Seq.map (rpair cases) (Seq.INTERVAL tac2 i (i + nprems_of st' - nprems_of st) st')));
   280     Seq.map (rpair cases) (Seq.INTERVAL tac2 i (i + nprems_of st' - nprems_of st) st'));
   247 
   281 
   248 
   282 
   249 (* find rules *)
   283 (* find rules *)
   250 
   284 
   251 (* rename all outermost !!-bound vars of type T in all premises of thm to x,
   285 (*rename all outermost !!-bound vars of type T in all premises of thm to x,
   252    possibly indexed to avoid clashes *)
   286   possibly indexed to avoid clashes*)
   253 fun rename [[SOME(Free(x,Type(T,_)))]] thm =
   287 fun rename [[SOME (Free (x, Type (T, _)))]] thm =
   254   let
   288       let
   255     fun index i [] = []
   289         fun index i [] = []
   256       | index i (y::ys) = if x=y then x^string_of_int i :: index (i+1) ys
   290           | index i (y :: ys) =
   257                           else y :: index i ys;
   291               if x = y then x ^ string_of_int i :: index (i + 1) ys
   258     fun rename_params [] = []
   292               else y :: index i ys;
   259       | rename_params ((y,Type(U,_))::ys) =
   293         fun rename_params [] = []
   260           (if U=T then x else y)::rename_params ys
   294           | rename_params ((y, Type (U, _)) :: ys) =
   261       | rename_params ((y,_)::ys) = y::rename_params ys;
   295               (if U = T then x else y) :: rename_params ys
   262     fun rename_asm (A:term):term = 
   296           | rename_params ((y, _) :: ys) = y :: rename_params ys;
   263       let val xs = rename_params (Logic.strip_params A)
   297         fun rename_asm A =
   264           val xs' = case List.filter (equal x) xs of
   298           let
   265                       [] => xs | [_] => xs | _ => index 1 xs
   299             val xs = rename_params (Logic.strip_params A);
   266       in Logic.list_rename_params (xs',A) end;
   300             val xs' =
   267     fun rename_prop (p:term) =
   301               (case List.filter (equal x) xs of
   268       let val (As,C) = Logic.strip_horn p
   302                 [] => xs | [_] => xs | _ => index 1 xs);
   269       in Logic.list_implies(map rename_asm As, C) end;
   303           in Logic.list_rename_params (xs', A) end;
   270     val cp' = cterm_fun rename_prop (cprop_of thm);
   304         fun rename_prop p =
   271     val thm' = equal_elim (reflexive cp') thm
   305           let val (As, C) = Logic.strip_horn p
   272   in Thm.put_name_tags (Thm.get_name_tags thm) thm' end
   306           in Logic.list_implies (map rename_asm As, C) end;
       
   307         val cp' = cterm_fun rename_prop (Thm.cprop_of thm);
       
   308         val thm' = Thm.equal_elim (Thm.reflexive cp') thm;
       
   309       in Thm.put_name_tags (Thm.get_name_tags thm) thm' end
   273   | rename _ thm = thm;
   310   | rename _ thm = thm;
   274 
   311 
   275 fun find_inductT ctxt insts =
   312 fun find_inductT ctxt insts =
   276   foldr multiply [[]] (insts |> List.mapPartial (fn [] => NONE | ts => List.last ts)
   313   fold_rev multiply (insts |> List.mapPartial (fn [] => NONE | ts => List.last ts)
   277     |> map (InductAttrib.find_inductT ctxt o fastype_of))
   314     |> map (InductAttrib.find_inductT ctxt o fastype_of)) [[]]
   278   |> map join_rules |> List.concat |> map (rename insts);
   315   |> map join_rules |> List.concat |> map (rename insts);
   279 
   316 
   280 fun find_inductS ctxt (fact :: _) = InductAttrib.find_inductS ctxt fact
   317 fun find_inductS ctxt (fact :: _) = InductAttrib.find_inductS ctxt fact
   281   | find_inductS _ _ = [];
   318   | find_inductS _ _ = [];
   282 
   319 
   283 in
   320 in
   284 
   321 
       
   322 
   285 (* main tactic *)
   323 (* main tactic *)
   286 
   324 
   287 fun induct_tac ctxt is_open insts opt_rule facts =
   325 fun induct_tac ctxt is_open insts opt_rule fixes facts =
   288   let
   326   let
   289     val sg = ProofContext.sign_of ctxt;
   327     val thy = ProofContext.theory_of ctxt;
   290     val cert = Thm.cterm_of sg;
   328     val cert = Thm.cterm_of thy;
   291 
   329 
   292     fun rule_versions r = Seq.cons (r, Seq.filter (not o curry Thm.eq_thm r)
   330     fun rule_versions r = Seq.cons (r, Seq.filter (not o curry Thm.eq_thm r)
   293         (Seq.make (fn () => SOME (localize r, Seq.empty))))
   331         (Seq.make (fn () => SOME (localize r, Seq.empty))))
   294       |> Seq.map (rpair (RuleCases.get r));
   332       |> Seq.map (rpair (RuleCases.get r));
   295 
   333 
   296     val inst_rule = apfst (fn r =>
   334     val inst_rule = apfst (fn r =>
   297       if null insts then r
   335       if null insts then r
   298       else (align_right "Rule has fewer conclusions than arguments given"
   336       else (align_right "Rule has fewer conclusions than arguments given"
   299           (Data.dest_concls (Thm.concl_of r)) insts
   337           (Data.dest_concls (Thm.concl_of r)) insts
   300         |> (List.concat o map (prep_inst align_right cert (atomize_term sg)))
   338         |> (List.concat o map (prep_inst align_right cert (atomize_term thy)))
   301         |> Drule.cterm_instantiate) r);
   339         |> Drule.cterm_instantiate) r);
   302 
   340 
   303     val ruleq =
   341     val ruleq =
   304       (case opt_rule of
   342       (case opt_rule of
   305         NONE =>
   343         NONE =>
   306           let val rules = find_inductS ctxt facts @ find_inductT ctxt insts in
   344           let val rules = find_inductS ctxt facts @ find_inductT ctxt insts in
   307             conditional (null rules) (fn () => error "Unable to figure out induct rule");
   345             conditional (null rules) (fn () => error "Unable to figure out induct rule");
   308             Method.trace ctxt rules;
   346             Method.trace ctxt rules;
   309             rules |> Seq.THEN (Seq.of_list, Seq.THEN (rule_versions, Seq.try inst_rule))
   347             rules |> Seq.of_list |> Seq.maps rule_versions |> Seq.maps (Seq.try inst_rule)
   310           end
   348           end
   311       | SOME r => r |> Seq.THEN (rule_versions, Seq.single o inst_rule));
   349       | SOME r => r |> rule_versions |> Seq.map inst_rule);
   312 
   350 
   313     fun prep_rule (th, (cases, n)) =
   351     fun prep_rule (th, (cases, n)) =
   314       Seq.map (rpair (cases, n - length facts, Library.drop (n, facts)))
   352       Seq.map (rpair (cases, n - length facts, Library.drop (n, facts)))
   315         (Method.multi_resolves (Library.take (n, facts)) [th]);
   353         (Method.multi_resolves (Library.take (n, facts)) [th]);
   316     val tac = resolveq_cases_tac' RuleCases.make is_open (Seq.flat (Seq.map prep_rule ruleq));
   354     val tac = resolveq_cases_tac' ctxt RuleCases.make is_open (Seq.maps prep_rule ruleq) fixes;
   317   in tac THEN_ALL_NEW_CASES rulify_tac end;
   355   in tac THEN_ALL_NEW_CASES rulify_tac end;
   318 
   356 
   319 val induct_meth = Method.RAW_METHOD_CASES o ((Seq.DETERM o HEADGOAL) oo
   357 val induct_meth = Method.RAW_METHOD_CASES o ((Seq.DETERM o HEADGOAL) oo
   320   (fn (ctxt, (is_open, (insts, opt_rule))) => induct_tac ctxt is_open insts opt_rule));
   358   (fn (ctxt, (is_open, (insts, (opt_rule, fixes)))) =>
       
   359     induct_tac ctxt is_open insts opt_rule fixes));
   321 
   360 
   322 end;
   361 end;
   323 
   362 
   324 
   363 
   325 
   364 
   326 (** concrete syntax **)
   365 (** concrete syntax **)
   327 
   366 
   328 val openN = "open";
   367 val openN = "open";
   329 val ruleN = "rule";
   368 val ruleN = "rule";
   330 val ofN = "of";
   369 val ofN = "of";
       
   370 val fixingN = "fixing";
   331 
   371 
   332 local
   372 local
   333 
   373 
   334 fun named_rule k arg get =
   374 fun named_rule k arg get =
   335   Scan.lift (Args.$$$ k -- Args.colon) |-- arg :-- (fn name => Scan.peek (fn ctxt =>
   375   Scan.lift (Args.$$$ k -- Args.colon) |-- arg :-- (fn name => Scan.peek (fn ctxt =>
   342   Scan.lift (Args.$$$ ruleN -- Args.colon) |-- Attrib.local_thm;
   382   Scan.lift (Args.$$$ ruleN -- Args.colon) |-- Attrib.local_thm;
   343 
   383 
   344 val cases_rule = rule InductAttrib.lookup_casesT InductAttrib.lookup_casesS;
   384 val cases_rule = rule InductAttrib.lookup_casesT InductAttrib.lookup_casesS;
   345 val induct_rule = rule InductAttrib.lookup_inductT InductAttrib.lookup_inductS;
   385 val induct_rule = rule InductAttrib.lookup_inductT InductAttrib.lookup_inductS;
   346 
   386 
   347 val kind_inst =
   387 val more_args =
   348   (Args.$$$ InductAttrib.typeN || Args.$$$ InductAttrib.setN || Args.$$$ ruleN || Args.$$$ ofN)
   388   (Args.$$$ InductAttrib.typeN || Args.$$$ InductAttrib.setN || Args.$$$ ruleN ||
   349     -- Args.colon;
   389     Args.$$$ ofN || Args.$$$ fixingN) -- Args.colon;
   350 val term = Scan.unless (Scan.lift kind_inst) Args.local_term;
   390 
   351 val term_dummy = Scan.unless (Scan.lift kind_inst)
   391 val term = Scan.unless (Scan.lift more_args) Args.local_term;
       
   392 val term_dummy = Scan.unless (Scan.lift more_args)
   352   (Scan.lift (Args.$$$ "_") >> K NONE || Args.local_term >> SOME);
   393   (Scan.lift (Args.$$$ "_") >> K NONE || Args.local_term >> SOME);
   353 
   394 
   354 val instss = Args.and_list (Scan.repeat term_dummy);
   395 val instss = Args.and_list (Scan.repeat term_dummy);
   355 
   396 
       
   397 val free = Scan.state -- Args.local_term >> (fn (_, Free v) => v | (ctxt, t) =>
       
   398   error ("Bad free variable: " ^ ProofContext.string_of_term ctxt t));
       
   399 val fixing = Scan.optional (Scan.lift (Args.$$$ fixingN -- Args.colon) |-- Scan.repeat1 free) [];
       
   400 
   356 in
   401 in
   357 
   402 
   358 val cases_args = Method.syntax (Args.mode openN -- (instss -- Scan.option cases_rule));
   403 val cases_args =
   359 val induct_args = Method.syntax (Args.mode openN -- (instss -- Scan.option induct_rule));
   404   Method.syntax (Args.mode openN -- (instss -- Scan.option cases_rule));
       
   405 val induct_args =
       
   406   Method.syntax (Args.mode openN -- (instss -- (Scan.option induct_rule -- fixing)));
   360 
   407 
   361 end;
   408 end;
   362 
   409 
   363 
   410 
   364 
   411 
   368   [Method.add_methods
   415   [Method.add_methods
   369     [(InductAttrib.casesN, cases_meth oo cases_args, "case analysis on types or sets"),
   416     [(InductAttrib.casesN, cases_meth oo cases_args, "case analysis on types or sets"),
   370      (InductAttrib.inductN, induct_meth oo induct_args, "induction on types or sets")]];
   417      (InductAttrib.inductN, induct_meth oo induct_args, "induction on types or sets")]];
   371 
   418 
   372 end;
   419 end;
   373