# HG changeset patch # User wenzelm # Date 1214227612 -7200 # Node ID a12978a1126a469c0ea43e9cb45f4771ce4df4d1 # Parent 464ac1c815ec498eff85ff1b84e0f923390f3684 induct_tac: infer mutual rule from types, as for proper induct method; diff -r 464ac1c815ec -r a12978a1126a src/HOL/Tools/induct_tacs.ML --- a/src/HOL/Tools/induct_tacs.ML Mon Jun 23 15:26:51 2008 +0200 +++ b/src/HOL/Tools/induct_tacs.ML Mon Jun 23 15:26:52 2008 +0200 @@ -10,7 +10,7 @@ val case_tac: Proof.context -> string -> int -> tactic val case_rule_tac: Proof.context -> string -> thm -> int -> tactic val induct_tac: Proof.context -> string option list list -> int -> tactic - val induct_rule_tac: Proof.context -> string option list list -> thm -> int -> tactic + val induct_rules_tac: Proof.context -> string option list list -> thm list -> int -> tactic val setup: theory -> theory end @@ -25,7 +25,7 @@ val U = Term.fastype_of u; val _ = Term.is_TVar U andalso error ("Cannot determine type of " ^ Syntax.string_of_term ctxt u); - in U end; + in (u, U) end; fun gen_case_tac ctxt0 (s, opt_rule) i st = let @@ -35,7 +35,7 @@ SOME rule => rule | NONE => (case Induct.find_casesT ctxt - (check_type ctxt (ProofContext.read_term_schematic ctxt s)) of + (#2 (check_type ctxt (ProofContext.read_term_schematic ctxt s))) of rule :: _ => rule | [] => @{thm case_split})); val _ = Method.trace ctxt [rule]; @@ -64,7 +64,7 @@ in -fun gen_induct_tac ctxt0 (varss, opt_rule) i st = +fun gen_induct_tac ctxt0 (varss, opt_rules) i st = let val ((_, goal), ctxt) = Variable.focus_subgoal i st ctxt0; val (prems, concl) = Logic.strip_horn (Thm.term_of goal); @@ -82,31 +82,32 @@ if (exists o Term.exists_subterm) eq_x prems then warning ("Induction variable occurs also among premises: " ^ Syntax.string_of_term ctxt t) else (); - in check_type ctxt t end; + in #1 (check_type ctxt t) end; - val var_types = map_filter (Option.map induct_var) (flat varss); + val argss = map (map (Option.map induct_var)) varss; + val _ = forall null argss andalso raise THM ("No induction arguments", 0, []); + val rule = - (case opt_rule of - SOME rule => rule + (case opt_rules of + SOME rules => #2 (RuleCases.strict_mutual_rule ctxt rules) | NONE => - (case var_types of - T :: _ => - (case filter_out PureThy.is_internal (Induct.find_inductT ctxt T) of - rule :: _ => rule - | [] => raise THM ("No induction rules", 0, [])) - | _ => raise THM ("No induction arguments", 0, []))); - val _ = Method.trace ctxt [rule]; + (case map_filter (RuleCases.mutual_rule ctxt) (Induct.get_inductT ctxt argss) of + (_, rule) :: _ => rule + | [] => raise THM ("No induction rules", 0, []))); - val concls = HOLogic.dest_concls (Thm.concl_of rule); + val rule' = rule |> Conv.fconv_rule (Conv.concl_conv ~1 ObjectLogic.atomize); + val _ = Method.trace ctxt [rule']; + + val concls = Logic.dest_conjunctions (Thm.concl_of rule); val insts = maps prep_inst (concls ~~ varss) handle Library.UnequalLengths => error "Induction rule has different numbers of variables"; - in res_inst_tac ctxt insts rule i st end + in res_inst_tac ctxt insts rule' i st end handle THM _ => Seq.empty; end; fun induct_tac ctxt args = gen_induct_tac ctxt (args, NONE); -fun induct_rule_tac ctxt args rule = gen_induct_tac ctxt (args, SOME rule); +fun induct_rules_tac ctxt args rules = gen_induct_tac ctxt (args, SOME rules); (* method syntax *) @@ -115,6 +116,7 @@ val rule_spec = Scan.lift (Args.$$$ "rule" -- Args.$$$ ":"); val opt_rule = Scan.option (rule_spec |-- Attrib.thm); +val opt_rules = Scan.option (rule_spec |-- Attrib.thms); val varss = Args.and_list (Scan.repeat (Scan.unless rule_spec (Scan.lift (Args.maybe Args.name)))); @@ -125,7 +127,7 @@ Method.add_methods [("case_tac", Method.goal_args_ctxt' (Scan.lift Args.name -- opt_rule) gen_case_tac, "unstructured case analysis on types"), - ("induct_tac", Method.goal_args_ctxt' (varss -- opt_rule) gen_induct_tac, + ("induct_tac", Method.goal_args_ctxt' (varss -- opt_rules) gen_induct_tac, "unstructured induction on types")]; end;