(* Title: ZF/Tools/induct_tacs.ML Author: Lawrence C Paulson, Cambridge University Computer Laboratory Copyright 1994 University of Cambridge
Induction and exhaustion tactics for Isabelle/ZF. The theory information needed to support them (and to support primrec). Also a function to install other sets as if they were datatypes.
*)
signature DATATYPE_TACTICS = sig val exhaust_tac: Proof.context -> string -> (binding * stringoption * mixfix) list ->
int -> tactic val induct_tac: Proof.context -> string -> (binding * stringoption * mixfix) list ->
int -> tactic val rep_datatype_i: thm -> thm -> thm list -> thm list -> theory -> theory val rep_datatype: Facts.ref * Token.src list -> Facts.ref * Token.src list ->
(Facts.ref * Token.src list) list -> (Facts.ref * Token.src list) list -> theory -> theory end;
(** Datatype information, e.g. associated theorems **)
type datatype_info =
{inductive: bool, (*true if inductive, not coinductive*)
constructors : term list, (*the constructors, as Consts*)
rec_rewrites : thm list, (*recursor equations*)
case_rewrites : thm list, (*case equations*)
induct : thm,
mutual_induct : thm,
exhaustion : thm};
structure DatatypesData = Theory_Data
( type T = datatype_info Symtab.table; val empty = Symtab.empty; fun merge data : T = Symtab.merge (K true) data;
);
(** Constructor information: needed to map constructors to datatypes **)
type constructor_info =
{big_rec_name : string, (*name of the mutually recursive set*)
constructors : term list, (*the constructors, as Consts*)
free_iffs : thm list, (*freeness simprules*)
rec_rewrites : thm list}; (*recursor equations*)
structure ConstructorsData = Theory_Data
( type T = constructor_info Symtab.table val empty = Symtab.empty fun merge data = Symtab.merge (K true) data;
);
fun datatype_info thy name =
(case Symtab.lookup (DatatypesData.get thy) name of
SOME info => info
| NONE => error ("Unknown datatype " ^ quote name));
(*Given a variable, find the inductive set associated it in the assumptions*)
exception Find_tname ofstring
fun find_tname ctxt var As = letfun mk_pair \<^Const_>\<open>mem for \<open>Free (v,_)\<close> A\<close> = (v, dest_Const_name (head_of A))
| mk_pair _ = raiseMatch val pairs = map_filter (try (mk_pair o \<^dest_judgment>)) As val x =
(casetry (dest_Free o Syntax.read_term ctxt) var of
SOME (x, _) => x
| _ => raise Find_tname ("Bad variable " ^ quote var)) incase AList.lookup (op =) pairs x of
NONE => raise Find_tname ("Cannot determine datatype of " ^ quote var)
| SOME t => t end;
(** generic exhaustion and induction tactic for datatypes Differences from HOL: (1) no checking if the induction var occurs in premises, since it always appears in one of them, and it's hard to check for other occurrences (2) exhaustion works for VARIABLES in the premises, not general terms
**)
fun exhaust_induct_tac exh ctxt var fixes i state = SUBGOAL (fn _ => let val thy = Proof_Context.theory_of ctxt val ({context = ctxt', asms, ...}, _) = Subgoal.focus ctxt i NONE state val tn = find_tname ctxt' var (map Thm.term_of asms) val rule =
datatype_info thy tn
|> (if exh then #exhaustion else #induct)
|> Thm.transfer thy; val \<^Const_>\<open>mem for \<open>Var(ixn,_)\<close> _\<close> =
(case Thm.take_prems_of 1 rule of
[] => error "induction is not available for this datatype"
| major::_ => \<^dest_judgment> major) in
Rule_Insts.eres_inst_tac ctxt [((ixn, Position.none), var)] fixes rule i end handle Find_tname msg => if exh then(*try boolean case analysis instead*)
case_tac ctxt var fixes i else error msg) i state;
val exhaust_tac = exhaust_induct_tac true; val induct_tac = exhaust_induct_tac false;
(**** declare non-datatype as datatype ****)
fun rep_datatype_i elim induct case_eqns recursor_eqns thy = let (*analyze the LHS of a case equation to get a constructor*) fun const_of \<^Const_>\<open>IFOL.eq _ for \<open>_ $ c\<close> _\<close> = c
| const_of eqn = error ("Ill-formed case equation: " ^
Syntax.string_of_term_global thy eqn);
val constructors = map (head_of o const_of o \<^dest_judgment> o Thm.prop_of) case_eqns;
val \<^Const_>\<open>mem for _ data\<close> = \<^dest_judgment> (hd (Thm.take_prems_of 1 elim));
val con_info =
{big_rec_name = big_rec_name,
constructors = constructors, (*let primrec handle definition by cases*)
free_iffs = [], (*thus we expect the necessary freeness rewrites to be in the simpset already, as is the case for
Nat and disjoint sum*)
rec_rewrites =
(case recursor_eqns of [] => case_eqns | _ => recursor_eqns)
|> map Thm.trim_context};
(*associate with each constructor the datatype name and rewrites*) val con_pairs = map (fn c => (dest_Const_name c, con_info)) constructors
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.