# HG changeset patch # User wenzelm # Date 1213108958 -7200 # Node ID 22e8c115f6c949934d375d7aceba5399d02b036d # Parent ac87245d8cab921deb79011539b873f93a89ff5a Unstructured induction and cases analysis for Isabelle/HOL. diff -r ac87245d8cab -r 22e8c115f6c9 src/HOL/Tools/induct_tacs.ML --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/HOL/Tools/induct_tacs.ML Tue Jun 10 16:42:38 2008 +0200 @@ -0,0 +1,126 @@ +(* Title: HOL/Tools/induct_tacs.ML + ID: $Id$ + Author: Makarius + +Unstructured induction and cases analysis for Isabelle/HOL. +*) + +signature INDUCT_TACS = +sig + val case_tac: Proof.context -> string * thm option -> int -> tactic + val induct_tac: Proof.context -> string option list list * thm option -> int -> tactic + val setup: theory -> theory +end + +structure InductTacs: INDUCT_TACS = +struct + +(* case analysis *) + +fun check_type ctxt t = + let + val u = singleton (Variable.polymorphic ctxt) t; + 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; + +fun case_tac ctxt0 (s, opt_rule) i st = + let + val ((_, goal), ctxt) = Variable.focus_subgoal i st ctxt0; + val rule = + (case opt_rule of + SOME rule => rule + | NONE => + (case Induct.find_casesT ctxt + (check_type ctxt (ProofContext.read_term_schematic ctxt s)) of + rule :: _ => rule + | [] => @{thm case_split})); + val _ = Method.trace ctxt [rule]; + + val xi = + (case Induct.vars_of (Thm.term_of (Thm.cprem_of rule 1)) of + Var (xi, _) :: _ => xi + | _ => raise THM ("Malformed cases rule", 0, [rule])); + in RuleInsts.res_inst_tac ctxt [(xi, s)] rule i st end + handle THM _ => Seq.empty; + + +(* induction *) + +local + +fun prep_var (Var (ixn, _), SOME x) = SOME (ixn, x) + | prep_var _ = NONE; + +fun prep_inst (concl, xs) = + let val vs = Induct.vars_of concl + in map_filter prep_var (Library.drop (length vs - length xs, vs) ~~ xs) end; + +in + +fun induct_tac ctxt0 (varss, opt_rule) i st = + let + val ((_, goal), ctxt) = Variable.focus_subgoal i st ctxt0; + val (prems, concl) = Logic.strip_horn (Thm.term_of goal); + + fun induct_var name = + let + val t = Syntax.read_term ctxt name; + val (x, _) = Term.dest_Free t handle TERM _ => + error ("Induction argument not a variable: " ^ Syntax.string_of_term ctxt t); + val eq_x = fn Free (y, _) => x = y | _ => false; + val _ = + if Term.exists_subterm eq_x concl then () + else error ("No such variable in subgoal: " ^ Syntax.string_of_term ctxt t); + val _ = + 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; + + val var_types = map_filter (Option.map induct_var) (flat varss); + val rule = + (case opt_rule of + SOME rule => rule + | 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]; + + val concls = HOLogic.dest_concls (Thm.concl_of rule); + val insts = maps prep_inst (concls ~~ varss) handle Library.UnequalLengths => + error "Induction rule has different numbers of variables"; + in RuleInsts.res_inst_tac ctxt insts rule i st end + handle THM _ => Seq.empty; + +end; + + +(* method syntax *) + +local + +val rule_spec = Scan.lift (Args.$$$ "rule" -- Args.$$$ ":"); +val opt_rule = Scan.option (rule_spec |-- Attrib.thm); + +val varss = + Args.and_list (Scan.repeat (Scan.unless rule_spec (Scan.lift (Args.maybe Args.name)))); + +in + +val setup = + Method.add_methods + [("case_tac", Method.goal_args_ctxt' (Scan.lift Args.name -- opt_rule) case_tac, + "unstructured case analysis on types"), + ("induct_tac", Method.goal_args_ctxt' (varss -- opt_rule) induct_tac, + "unstructured induction on types")]; + +end; + +end; +