(* ========================================================================= *)
(* Isabelle Light *)
(* Isabelle/Procedural style additions and other user-friendly shortcuts. *)
(* *)
(* Petros Papapanagiotou, Jacques Fleuriot *)
(* Center of Intelligent Systems and their Applications *)
(* University of Edinburgh *)
(* 2009-2012 *)
(* ========================================================================= *)
(* FILE : meta_rules.ml *)
(* DESCRIPTION : Meta rules is a formalisation used to accommodate *)
(* Isabelle's inference rules in HOL Light.The technical *)
(* details are described in the comments that follow. *)
(* Isabelle rule application tactics (rule, erule, etc.) have *)
(* been defined to work with meta rules. *)
(* We have not been able to accommodate first order rules *)
(* allI and exE. We also make use of metavariables which are *)
(* restricted by the limitations of term_unify *)
(* (ie. no HO unification and no type instantiation). *)
(* LAST MODIFIED: October 2012 *)
(* ========================================================================= *)
(* ------------------------------------------------------------------------- *)
(* ----------------------- META-LEVEL IMPLICATION -------------------------- *)
(* ------------------------------------------------------------------------- *)
(* Emulation of meta-level implication at the object level. *)
(* This is purely for syntax and parsing purposes. It solves a number of *)
(* problems when parsing theorems as meta-rules (see below). *)
(* It is applied at the logic level only for transparency. *)
(* ------------------------------------------------------------------------- *)
(* Thanks to Phil Scott for the suggestion. *)
(* ------------------------------------------------------------------------- *)
(* ------------------------------------------------------------------------- *)
(* Syntax definition. *)
(* ------------------------------------------------------------------------- *)
parse_as_infix ("===>",(4,"right"));;
let is_mimp = is_binary "===>";;
let dest_mimp = dest_binary "===>";;
(* ------------------------------------------------------------------------- *)
(* Logic definition: Equivalent to object-level implication. *)
(* ------------------------------------------------------------------------- *)
let MIMP_DEF = new_basic_definition
`(===>) = \p q. p ==> q`;;
(* ------------------------------------------------------------------------- *)
(* CONV, RULE and TACTIC to get rid of meta-level implication in proofs. *)
(* ------------------------------------------------------------------------- *)
let MIMP_TO_IMP_CONV = BETA_RULE o (PURE_REWRITE_CONV [MIMP_DEF]);;
let MIMP_TO_IMP_RULE = BETA_RULE o (PURE_REWRITE_RULE [MIMP_DEF]);;
let MIMP_TAC = (PURE_REWRITE_TAC [MIMP_DEF]) THEN BETA_TAC;;
(* ------------------------------------------------------------------------- *)
(* Equivalent of TAUT after getting rid of meta-level implication. *)
(* Helps prove simple propositional meta-rules easily. *)
(* ------------------------------------------------------------------------- *)
let MTAUT tm =
let th = MIMP_TO_IMP_CONV tm in
EQ_MP (SYM th) ((TAUT o snd o dest_iff o concl) th);;
(* ------------------------------------------------------------------------- *)
(* RULE to replace implication by meta-level implication to easily create *)
(* meta-theorems from normal theorems. *)
(* ------------------------------------------------------------------------- *)
let MIMP_THM = MTAUT `(p==>q) <=> (p===>q)`;;
let MIMP_RULE = PURE_REWRITE_RULE[MIMP_THM];;
(* ------------------------------------------------------------------------- *)
(* UNDISCH for meta-level implication. *)
(* Also gets rid of meta-level implication in the undischarged term. *)
(* ------------------------------------------------------------------------- *)
let MUNDISCH th =
let mth = BETA_RULE (AP_THM (AP_THM MIMP_DEF `p:bool`) `q:bool`) in
let th = PURE_ONCE_REWRITE_RULE [mth] th in
try let undisch_tm = (rand o rator o concl) th in
PROVE_HYP ((UNDISCH o snd o EQ_IMP_RULE o MIMP_TO_IMP_CONV) undisch_tm) (UNDISCH th)
with Failure _ -> failwith "MUNDISCH";;
(* ------------------------------------------------------------------------- *)
(* -------------------------- HELPFUL FUNCTIONS ---------------------------- *)
(* ------------------------------------------------------------------------- *)
(* ------------------------------------------------------------------------- *)
(* REV_PART_MATCH_I: term list -> (term -> term) -> thm -> term *)
(* -> instantiation *)
(* Does a reverse PART_MATCH and returns the resulting instantiation. *)
(* Avoids instantiating any of the given variables/constants. *)
(* Does not apply SPEC_ALL like PART_MATCH does. *)
(* ------------------------------------------------------------------------- *)
(* The original PART_MATCH matches a term to part of a theorem so that we can*)
(* instantiate that part with the term. *)
(* The reverse used here, matches the part of the theorem with the term so *)
(* that the term can be instantiated with the part of the theorem. *)
(* We use this in cases such as erule where we want (part of) an assumption *)
(* to match a premise of the rule. We need the instantiation of the rule when*)
(* matched to the assumption (thm) and not the other way around. *)
(* ------------------------------------------------------------------------- *)
let REV_PART_MATCH_I =
let rec match_bvs t1 t2 acc =
try let v1,b1 = dest_abs t1
and v2,b2 = dest_abs t2 in
let n1 = fst(dest_var v1) and n2 = fst(dest_var v2) in
let newacc = if n1 = n2 then acc else insert (n1,n2) acc in
match_bvs b1 b2 newacc
with Failure _ -> try
let l1,r1 = dest_comb t1
and l2,r2 = dest_comb t2 in
match_bvs l1 l2 (match_bvs r1 r2 acc)
with Failure _ -> acc in
fun avoids partfn th ->
let bod = concl th in
let pbod = partfn bod in
let lconsts = union avoids (intersect (frees (concl th)) (freesl(hyp th))) in
fun tm ->
let bvms = match_bvs pbod tm [] in
let atm = deep_alpha bvms tm in
term_match lconsts atm (partfn bod) ;; (* whereas in PART_MATCH we do it the other way around *)
(* ------------------------------------------------------------------------- *)
(* term_to_asm_match : term list -> term -> (string * thm) list -> *)
(* (string * thm) list * (thm * instantiation) *)
(* ------------------------------------------------------------------------- *)
(* term_to_asm_match tries to match key to one of the assumptions using *)
(* REV_PART_MATCH_I. Returns the new assumption list (with the matching *)
(* assumption removed), the matching assumption and the resulting *)
(* instantiation used. *)
(* ------------------------------------------------------------------------- *)
(* It is doubtful that this has practical use outside the Xrule_tac's. *)
(* It is used in erule, drule and frule to match the major premise to one of *)
(* the assumptions. *)
(* ------------------------------------------------------------------------- *)
let rec (term_to_asm_match: term list -> term -> (string * thm) list -> (string * thm) list * (thm * instantiation)) =
fun avoids key asms ->
if (asms = []) then failwith ("No assumptions match `" ^ (string_of_term key) ^ "`!")
else try
let asm = (snd o hd) asms in
let i = REV_PART_MATCH_I avoids I asm key in
(tl asms),(asm,i)
with Failure _ -> let res,inst = term_to_asm_match avoids key (tl asms) in ((hd asms)::res),inst;;
(* ------------------------------------------------------------------------- *)
(* term_to_asm_n_match : term list -> term -> (string * thm) list -> int -> *)
(* (string * thm) list * (thm * instantiation) *)
(* ------------------------------------------------------------------------- *)
(* Same as term_to_asm_match but only tries to match nth assumption. *)
(* ------------------------------------------------------------------------- *)
(* It is doubtful that this has practical use outside the Xrulen_tac's. *)
(* It is used in erulen, drulen and frulen to match the major premise to one *)
(* of the assumptions. *)
(* ------------------------------------------------------------------------- *)
let rec (term_to_asm_n_match: term list -> term -> (string * thm) list -> int -> (string * thm) list * (thm * instantiation)) =
fun avoids key asms n ->
if (asms = []) then failwith "No such assumption found!"
else try match n with
0 ->
let asm = (snd o hd) asms in
let i = REV_PART_MATCH_I avoids I asm key in
(tl asms),(asm,i)
| _ -> let re_asms,m = term_to_asm_n_match avoids key (tl asms) (n-1) in
(hd asms)::re_asms,m
with Failure _ -> failwith ("Assumption `" ^ ((string_of_term o concl o snd o hd) asms) ^ "` doesn't match `" ^ (string_of_term key) ^ "`!");;
(* gmm is not to be used until qed is updated *)
(* We need a MDISCH for that... *)
let gmm t =
let fvs = sort (<) (map (fst o dest_var) (frees t)) in
(if fvs <> [] then
let errmsg = end_itlist (fun s t -> s^", "^t) fvs in
warn true ("Free variables in goal: "^errmsg)
else ());
let rec split_mimp = fun tm ->
if (is_mimp tm)
then
let (a,b) = dest_mimp tm in
let (asms, concl) = split_mimp b in
(a::asms,concl)
else ([],tm) in
set_goal (split_mimp t);;
(* ------------------------------------------------------------------------- *)
(* gm : term -> goalstack *)
(* This is used to set a term containing meta-level implication as a goal. *)
(* ------------------------------------------------------------------------- *)
(* (+) Uses g to set the goal then MIMP_TAC to get rid of meta-implication. *)
(* (+) Note that if the goal has normal implication it gets discharged as *)
(* well. This will be fixed when gmm is fixed. *)
(* ------------------------------------------------------------------------- *)
let gm t = g t ; e (MIMP_TAC THEN REPEAT DISCH_TAC);;
(* ------------------------------------------------------------------------- *)
(* Isabelle's natural deduction rules as thms with meta-level implication. *)
(* ------------------------------------------------------------------------- *)
let conjI = MTAUT `p===>q===>p/\q`;;
let conjunct1 = MTAUT `p/\q===>p`;;
let conjunct2 = MTAUT `p/\q===>q`;;
let conjE = MTAUT `p/\q===>(p===>q===>r)===>r`;;
let disjI1 = MTAUT `p===>p\/q`;;
let disjI2 = MTAUT `q===>p\/q`;;
let disjE = MTAUT `p\/q===>(p===>r)===>(q===>r)===>r`;;
let impI = MTAUT `(p===>q)===>(p==>q)`;;
let impE = MTAUT `(p==>q)===>p===>(q===>r)===>r`;;
let mp = MTAUT `(p==>q)===>(p===>q)`;;
let iffI = MTAUT `(a===>b)===>(b===>a)===>(a<=>b)`;;
let iffE = MTAUT `(a<=>b)===>((a==>b) ===> (b==>a) ===> r) ===> r`;;
let allE = prove( `(!x:A. P x) ===> (P (a:A) ===> (r:bool)) ===> r` ,
MIMP_TAC THEN MESON_TAC[]);;
let exI = prove (`P (a:A)===> ?x:A. P x`,
MIMP_TAC THEN
DISCH_TAC THEN
(EXISTS_TAC `a:A`) THEN
(FIRST_ASSUM ACCEPT_TAC));;
let notI = MTAUT `(p===>F)===> ~p`;;
let notE = MTAUT `~a ===> a ===> r`;;
(* ------------------------------------------------------------------------- *)
(* ------------------------------------------------------------------------- *)
(* ------------------------ META-RULES START HERE!! ------------------------ *)
(* ------------------------------------------------------------------------- *)
(* ------------------------------------------------------------------------- *)
(* ------------------------------------------------------------------------- *)
(* meta_rule (type) *)
(* The representation of an Isabelle inference rule in HOL Light. *)
(* ------------------------------------------------------------------------- *)
(* term = The conclusion of the inference rule. *)
(* goal list = The premises represented as "meta-subgoals". *)
(* thm = The representation of the rule as a theorem used for justification. *)
(* *)
(* (+) thm must be of the form H1,H2,...,Hn |- G *)
(* (+) H1--Hn must be represented as "meta-subgoals" in any order (1) *)
(* (+) [|P;Q|] ==> R (in Isabelle notation) is translated as "meta-subgoal" *)
(* P,Q ?- R and as P==>Q==>R in the justification theorem. *)
(* (+) The form of the premises (assumption order etc) must be kept in the *)
(* justification theorem (see example in (2)) *)
(* (+) Use "mk_meta_rule" to create proper meta rules from theorems. *)
(* ------------------------------------------------------------------------- *)
(* (1) Since we use PROVE_HYP instead of MP to justify rule, erule etc, the *)
(* order of the subgoals is no longer essential. *)
(* (2) Example: conjE *)
(* In Isabelle: P/\Q [|P;Q|]==> R *)
(* ------------------ *)
(* R *)
(* *)
(* As a meta rule (briefly - see conjEm below for full notation): *)
(* `R`, - conclusion *)
(* [ - premises list *)
(* [ ], `P/\Q` ; *)
(* [`P`;`Q`], `R` *)
(* ], *)
(* `P/\Q, P==>Q==>R |- R` - justification theorem *)
(* *)
(* The form of the premises must be preserved in the justification theorem. *)
(* ie. using `P/\Q, Q==>P==>R |- R` or `Q/\P, P==>Q==>R |- R` as a *)
(* justification theorem would break the justification and result in an *)
(* "invalid tactic" exception. *)
(* ------------------------------------------------------------------------- *)
type meta_rule = term * goal list * thm;;
let print_meta_rule: meta_rule->unit =
fun (c,glist,j) ->
print_term c ; hd (map (print_newline () ; print_goal) glist) ;
print_newline () ; print_thm j ; print_newline ();;
(* ------------------------------------------------------------------------- *)
(* inst_meta_rule: instantiation -> meta_rule -> meta_rule *)
(* ------------------------------------------------------------------------- *)
(* Instantiates all parts of meta_rules based on an instantiation. *)
(* ------------------------------------------------------------------------- *)
let inst_meta_rule:instantiation->meta_rule->meta_rule =
fun inst (c,glist,j) ->
instantiate inst c,
map (inst_goal inst) glist,
INSTANTIATE_ALL inst j;;
(* ------------------------------------------------------------------------- *)
(* meta_rule_frees: meta_rule -> term list *)
(* ------------------------------------------------------------------------- *)
(* Returns the list of free variables (or Isabelle ?metavariables) in a *)
(* meta_rule. *)
(* ------------------------------------------------------------------------- *)
let meta_rule_frees: meta_rule -> term list =
fun (c,glist,l) ->
itlist (union o gl_frees) glist (union (frees c) (thm_frees l));;
(* ------------------------------------------------------------------------- *)
(* meta_rule_mk_primed_vars_I: term_list -> meta_rule -> *)
(* meta_rule * instantiation *)
(* ------------------------------------------------------------------------- *)
(* Applies mk_primed_var to all the free variables in a meta_rule. *)
(* Returns the new meta_rule and the instantiation for the variable renaming.*)
(* ------------------------------------------------------------------------- *)
let meta_rule_mk_primed_vars_I: term list -> meta_rule -> meta_rule * instantiation =
fun avoids r ->
let fvars = meta_rule_frees r in
let rec mk_primed_l = fun avoids vars ->
match vars with
[] -> null_inst
| v::rest ->
let new_v = mk_primed_var avoids v in
compose_insts (term_match [] v new_v) (mk_primed_l (new_v::avoids) rest)
in
let inst = mk_primed_l avoids fvars in
(inst_meta_rule inst r),inst;;
(* ------------------------------------------------------------------------- *)
(* meta_rule_mk_primed_vars: term_list -> meta_rule -> meta_rule *)
(* ------------------------------------------------------------------------- *)
(* Applies mk_primed_var to all the free variables in a meta_rule. *)
(* ------------------------------------------------------------------------- *)
let meta_rule_mk_primed_vars: term list -> meta_rule -> meta_rule =
fun avoids r -> fst (meta_rule_mk_primed_vars_I avoids r);;
(* ------------------------------------------------------------------------- *)
(* inst_meta_rule_vars: *)
(* (term * term) list -> meta_rule -> term list -> meta_rule *)
(* ------------------------------------------------------------------------- *)
(* Instantiates the free variables in a meta_rule. Also renames the *)
(* uninstantiated variables so as to avoid clashes with free variables and *)
(* constants in the given goal. *)
(* Essentially it prepares the meta_rule for use with any of xrulem_tac. *)
(* ------------------------------------------------------------------------- *)
(* (+) By instlist we mean the list of variables and instantiation pairs *)
(* given by the user. *)
(* (+) First we check the terms given as variables in the instlist. We must *)
(* check if they are indeed variables and if they are free variables in the *)
(* given meta_rule. *)
(* (+) "match_var" is used to compare a variable with a free variable in the *)
(* meta_rule. *NOTE* that a variable is accepted as long as it can match a *)
(* free variable in the meta_rule allowing only type instantiation. *)
(* (+) "mcheck_var" does the is_var check and tries to find a match with the *)
(* meta_rule's free vars (rfrees) using match_var. *)
(* (+) "mcheck_gvar" tries to match variables on the rhs of each instlist *)
(* pair with the free variables in the goal so as to instantiate their types *)
(* properly. This is done to free the user from declaring the variable types.*)
(* (+) Given variables are replaced with the meta_rule variables (effectively*)
(* achieving type instantiation) and later recombined into the instlist. *)
(* (+) Secondly, we rename all the variables in the meta_rule using *)
(* "meta_rule_mk_primed_vars_I" so that they don't match any of the free *)
(* variables in the goal. *)
(* (+) We use the same instantiation to rename instlist variables so that *)
(* they properly match the new variables of the meta_rule. *)
(* (+) "new_instlist" should contain variables that fully match primed *)
(* variables in the meta_rule (new_r). *)
(* (+) For each instlist pair, we find the instantiation that allows the *)
(* variable to be substituted by the given term. *NOTE* that no check is *)
(* made on that term. It is the user's responsibility to give a sensible, *)
(* matching and correctly typed term. *)
(* (+) All the instantiations produced by the instlist are composed into one *)
(* which is then applied to new_r to give the result. *)
(* ------------------------------------------------------------------------- *)
let inst_meta_rule_vars: (term * term) list -> meta_rule -> term list -> meta_rule =
fun instlist r gfrees ->
let rfrees = meta_rule_frees r in
let vars,subs = List.split instlist in
let match_var = fun tm1 tm2 ->
let inst = try term_match [] tm1 tm2 with Failure _ -> [],[tm2,tm1],[] in
match inst with
[],[],_ -> tm2
| _ -> failwith "match_var: no match" in
let mcheck_var = fun tm ->
if (not (is_var tm)) then failwith ("inst_meta_rule_vars: `" ^ string_of_term tm ^ "` is not a variable")
else try list_match_first (match_var tm) rfrees
with Failure _ -> failwith ("inst_meta_rule_vars: `" ^ string_of_term tm ^ "` could not be found in the meta_rule") in
let mcheck_gvar = fun var ->
try let mvar = list_match_first (match_var var) gfrees in
term_match [] var mvar
with Failure _ ->
warn true ("inst_meta_rule_vars: `" ^ string_of_term var ^ "` could not be found in the goal") ;
null_inst in
let new_r,prim_inst = meta_rule_mk_primed_vars_I gfrees r in
let new_vars = map ((instantiate prim_inst) o mcheck_var) vars in
let subs_vars = flat (map frees subs) in
let new_subs_inst = itlist compose_insts (map mcheck_gvar subs_vars) null_inst in
let new_subs = map (instantiate new_subs_inst) subs in
let new_instlist = List.combine new_vars new_subs in
let mk_inst = fun t1,t2 -> term_match [] t1 t2 in
let inst = itlist compose_insts (map mk_inst new_instlist) null_inst in
let result_r = inst_meta_rule inst new_r in
result_r;;
(* ------------------------------------------------------------------------- *)
(* mk_meta_rule: thm -> meta_rule *)
(* Creates a meta_rule out of a theorem. *)
(* Theorem must be of the form |- H1 ===> H2 ===> ...===> Hn ===> C *)
(* "===>" is the emulation of meta-level implication so this corresponds to *)
(* [|H1;H2;...;Hn|] ==> C in Isabelle) *)
(* For each Hi that is a meta-level implication, a "meta_subgoal" is created.*)
(* ------------------------------------------------------------------------- *)
(* (+) undisch_premises uses MUNDISCH to handle meta-level implication. All *)
(* the premises are undischarged. It returns the list of premises paired *)
(* with the resulting theorem. Note that MUNDISCH also removes meta-level *)
(* implication from the undischarged premises. *)
(* (+) "mk_meta_subgoal" creates a meta_subgoal from a term. If the term is *)
(* an implication, the lhs is added as an assumption/premise of the *)
(* meta_subgoal and mk_meta_subgoal is called recursively for the rhs. *)
(* (+) The conclusion of the undischarged theorem is the first part of the *)
(* produced meta_rule. *)
(* (+) mk_meta_subgoal creates the meta_subgoals for all the premises. They *)
(* form the second part of the meta_rule. *)
(* (+) The theorem itself is used as the justification theorem, after *)
(* eliminating any remaining meta-level implication in the conclusion. *)
(* In theory, the conclusion should never have any remaining meta-level *)
(* implications. We're just making sure because we don't want any meta-level *)
(* implications to appear in our new subgoals. *)
(* ------------------------------------------------------------------------- *)
let (mk_meta_rule: thm -> meta_rule) =
fun thm ->
let rec undisch_premises th =
if is_mimp (concl th)
then let rest,res_th = undisch_premises (MUNDISCH th) in
(rand(rator(concl th)))::rest,res_th
else [],th in
let (prems,thm) = undisch_premises thm in
let rec mk_meta_subgoal tm = (
if (is_mimp(tm)) then
let (a,c) = dest_mimp tm in
let (prems,concl) = mk_meta_subgoal c in
("",ASSUME a)::prems,concl
else [],tm
) in
concl thm,map mk_meta_subgoal prems,MIMP_TO_IMP_RULE thm;;
(* ------------------------------------------------------------------------- *)
(* mk_meta_rule_old: thm -> meta_rule *)
(* Creates a meta_rule out of a theorem. === DEPRECATED === *)
(* Theorem must be of the form H1,H2,...,Hn |- C *)
(* If Hi is of the form Hi1==>Hi2==>...==>Hik==>HiC then it is treated as *)
(* Hi1,Hi2,...,Hik ?- HiC (or "meta-level" implication *)
(* [|Hi1;Hi2;...;Hik|] ==> HiC in Isabelle) and the corresponding *)
(* meta_subgoal is created. *)
(* ------------------------------------------------------------------------- *)
(* --As a result you CANNOT have rules with implication in their premises!-- *)
(* (You'll have to use mk_elim_meta_rule or build the meta_rule yourself.) *)
(* ------------------------------------------------------------------------- *)
(* (+) The theorem is destroyed to its hypothesis list and its conclusion. *)
(* The conclusion is the first part of the meta_rule. *)
(* (+) "mk_meta_subgoal" creates a meta_subgoal from a term. If the term is *)
(* an implication, the lhs is added as an assumption/premise of the *)
(* meta_subgoal and mk_meta_subgoal is called recursively for the rhs. *)
(* (+) The theorem itself is used as the justification theorem. *)
(* ------------------------------------------------------------------------- *)
(* Deprecated. New mk_meta_rule uses meta-level implication. *)
(* Kept until new mk_meta_rule is tested and stable. *)
(* ------------------------------------------------------------------------- *)
let (mk_meta_rule_old: thm -> meta_rule) =
fun thm ->
let (hyps,concl) = dest_thm thm in
let rec mk_meta_subgoal tm = (
if (is_imp(tm)) then
let (a,c) = dest_imp tm in
let (prems,concl) = mk_meta_subgoal c in
("",ASSUME a)::prems,concl
else [],tm
) in
concl,map mk_meta_subgoal hyps,thm;;
(* ------------------------------------------------------------------------- *)
(* mk_elim_meta_rule_old: thm -> meta_rule *)
(* Creates a meta_rule out of a theorem. === DEPRECATED === *)
(* Works like mk_meta_rule but acommodates elimination/destruction rules *)
(* a little bit better by not breaking the major premise. This effectively *)
(* allows the major premise to be an implication. *)
(* ------------------------------------------------------------------------- *)
(* In an elimination or destruction rule, the first or major premise is *)
(* matched against one of the assumptions. Therefore, you cannot have a *)
(* meta_subgoal for a major premise. If there is an implication there we *)
(* shall leave it intact and not treat it as "meta-level" implication. *)
(* This still disallows the use of implication in the rest of the premises *)
(* (by treating it as "meta-level" implication). *)
(* ------------------------------------------------------------------------- *)
(* Deprecated. New mk_meta_rule uses meta-level implication. *)
(* Kept until new mk_meta_rule is tested and stable. *)
(* ------------------------------------------------------------------------- *)
let (mk_elim_meta_rule_old: thm -> meta_rule) =
fun thm ->
let (hyps,concl) = dest_thm thm in
if (hyps = []) then failwith "mk_elim_meta_rule: Invalid rule - no premises!"
else let major_prem,hyps = ([],hd hyps),tl hyps in
let rec mk_meta_subgoal tm = (
if (is_imp(tm)) then
let (a,c) = dest_imp tm in
let (prems,concl) = mk_meta_subgoal c in
("",ASSUME a)::prems,concl
else [],tm
) in
concl,major_prem :: (map mk_meta_subgoal hyps),thm;;
(* ------------------------------------------------------------------------- *)
(* Isabelle's natural deduction inference rules as meta_rules. *)
(* ------------------------------------------------------------------------- *)
(* The trailing 'm' indicates they are represented as meta_rules as opposed *)
(* to theorems. *)
(* Use "mk_meta_rule" to create meta_rules from theorems. *)
(* Most of the following can be created using mk_meta_rule but are left here *)
(* as examples. *)
(* ------------------------------------------------------------------------- *)
(* Deprecated. New mk_meta_rule uses meta-level implication so now ALL of *)
(* these can be represented at the object-level and turned into meta_rules *)
(* using mk_meta_rule. *)
(* ------------------------------------------------------------------------- *)
let conjIm:meta_rule =
(`p/\q`,
[
[],`p:bool`;
[],`q:bool`
],
conjI);;
let conjEm:meta_rule =
(`r:bool`,
[
[],`p/\q`;
[("",ASSUME `p:bool`);("",ASSUME `q:bool`)],`r:bool`
],
(UNDISCH o UNDISCH o TAUT) `p/\q==>(p==>q==>r)==>r`
);;
let notEm:meta_rule =
(`r:bool`,
[
[],`~a`;
[],`a:bool`
],
(UNDISCH o UNDISCH o TAUT) `~a==>a==>r`
);;
let disjI1m:meta_rule =
(`p\/q`,
[
[],`p:bool`;
],
UNDISCH ( TAUT `p==>p\/q` ));;
let disjI2m:meta_rule =
(`p\/q`,
[
[],`q:bool`;
],
UNDISCH ( TAUT `q==>p\/q` ));;
let disjEm:meta_rule =
(`r:bool`,
[
[],`p\/q`;
[("",ASSUME `p:bool`)],`r:bool`;
[("",ASSUME `q:bool`)],`r:bool`
],
(UNDISCH o UNDISCH o UNDISCH) ( TAUT `p\/q==>(p==>r)==>(q==>r)==>r`)
);;
let impIm:meta_rule =
(`p==>q`,
[
[("",ASSUME `p:bool`)],`q:bool`
],
UNDISCH (TAUT `(p==>q)==>(p==>q)`)
);;
let impEm:meta_rule =
(`r:bool`,
[
[],`p==>q`;
[],`p:bool`;
[("",ASSUME `q:bool`)],`r:bool`
],
(UNDISCH o UNDISCH o UNDISCH o TAUT) `(p==>q)==>p==>(q==>r)==>r`
);;
let mpm:meta_rule =
(`q:bool`,
[
[],`p==>q`;
[],`p:bool`
],
(UNDISCH o UNDISCH o TAUT) `(p==>q)==>(p==>q)`
);;
(* Note from old mk_meta_rule: *)
(* This one cannot be expressed as a theorem because HOL Light insists on *)
(* ordering the assumptions of the theorem so the major premise is `p` *)
(* instead of `~p`. *)
let notEm:meta_rule =
(`r:bool`,
[
[],`~a`;
[],`a:bool`
],
(UNDISCH o UNDISCH o TAUT) `~a==>a==>r`
);;
(* ------------------------------------------------------------------------- *)
(* rulem_tac: ((term * term) list -> meta_rule -> tactic): *)
(* Isabelle's rule as a HOL Light meta_rule tactic. *)
(* Uses a rule of the form H1,H2,...,Hn |- C represented as a meta_rule *)
(* to solve A1,A2,...,Am ?- G *)
(* Matches C to the goal G, then splits the goal to *)
(* A1,A2,...,Am ?- H1 *)
(* A1,A2,...,Am ?- H2 *)
(* ... *)
(* A1,A2,...,Am ?- Hn *)
(* Hi can be of the form Hi1,Hi2,...,Hik ?- HiC then the goal produced is *)
(* A1,A2,...,Am,Hi1,Hi2,...,Hik ?- HiC *)
(* ------------------------------------------------------------------------- *)
(* (+) "avoids" lists all the free variables in the assumptions and goal so *)
(* as to avoid instantiating those (as in variable conflicts with the rule *)
(* or partly instantiated rule in the case of erule) *)
(* (+) First we check if C matches G. If it does we keep the resulting *)
(* instantiation (ins). *)
(* (+) We instantiate the "meta-subgoals" of the meta_rule using ins. *)
(* In essence we're instantiating the premises of the rule. (new_hyps) *)
(* (+) The "create_goal" function creates the new goals by adding the *)
(* assumption list A1--Am to the instantiated "meta-subgoal". *)
(* (+) create_goal is mapped on new_hyps to create the new subgoal list. *)
(* (+) The "create_dischl" function creates the list of the terms involved *)
(* in the premises of each instantiated meta-subgoal. In order to create the *)
(* justification of the tactic, we need to convert Hi1,Hi2,...,Hik |- HiC *)
(* into |- Hi1==>Hi2==>...==>Hik==>HiC. That is the only way we can capture *)
(* the notion of a "subgoal" within a HOL Light object-level theorem. *)
(* We will then use PROVE_HYP to eliminate each of the proven subgoals from *)
(* the rule's justification theorem. In order to achieve this conversion we *)
(* need to keep a list of the instantiated premises of the rule (dischls) *)
(* for each meta_subgoal so as to avoid discharging the original goal's *)
(* assumptions or _FALSITY_. *)
(* (+) "disch_pair" is used for convenience. dishls is combined with the *)
(* list of proven subgoals so that each subgoal is attached to its *)
(* corresponding premises list (dischl). disch_pair then does the discharges.*)
(* It also takes care of instantiating the meta-variables in those premises *)
(* for proper justification. *)
(* (+) normalfrees is used to calculate the list of metavariables that will *)
(* end up in the new subgoals. It contains all the free variables in the *)
(* goal and instlist. *)
(* (+) The newly introduced metavariables are found by subtracting *)
(* normalfrees from the set of all free variables in all new goals. *)
(* ------------------------------------------------------------------------- *)
let (rulem_tac: (term*term) list->meta_rule->tactic) =
fun instlist r ((asl,w) as g) ->
let (c,hyps,thm) = inst_meta_rule_vars instlist r (gl_frees g) in
let ins = try ( term_match [] c w ) with Failure _ -> failwith "Rule doesn't match!" in
let new_hyps = map (inst_goal ins) hyps in
let create_goal = fun asms (hs,gl) -> (hs@asms,gl) in
let new_goals = map (create_goal asl) new_hyps in
let rec create_dischl = fun (asms,g) -> if (asms = []) then [] else ((concl o snd o hd) asms)::(create_dischl ((tl asms),g)) in
let dischls = map create_dischl new_hyps in
let disch_pair = fun i (dischl,thm) -> DISCHL (map (instantiate i) dischl) thm in
let normalfrees = itlist union (map ( fun (_,y) -> frees y ) instlist ) (gl_frees g) in
let mvs = subtract (itlist union (map gl_frees new_goals) []) normalfrees in
(mvs,null_inst),new_goals,fun i l ->
List.fold_left (fun t1 t2 -> PROVE_HYP (INSTANTIATE_ALL i t2) t1) (INSTANTIATE_ALL (compose_insts ins i) thm) (map (disch_pair i) (List.combine dischls l));;
(* ------------------------------------------------------------------------- *)
(* erulem_tac: ((term * term) list -> meta_rule -> tactic): *)
(* Isabelle's erule as a HOL Light meta_rule tactic. *)
(* Works like rulem but also matches the first hypothesis H1 with one of the *)
(* assumptions A1--Am and instantiates accordingly. *)
(* A "proper" elimination rule H1 is of the form ?- H1 (ie. has no premises) *)
(* ------------------------------------------------------------------------- *)
(* Same as rulem with some added stuff. *)
(* (+) If there are no "meta_subgoals" (no new subgoals to create) we fail. *)
(* (+) Otherwise we use the first "meta_subgoal" as our primary hypothesis *)
(* (the one that will be eliminated - prim_hyp). *)
(* (+) If prim_hyp has premises then this is not a "proper" elimination rule.*)
(* (+) Otherwise try to match any of the assumptions with prim_hyp. The *)
(* resulting instantiation is elim_inst. *)
(* (+) Instantiate all generated meta_subgoals with elim_inst. Retrieve the *)
(* (now instantiated) prim_hyp and remove it from the new subgoals (it is *)
(* trivially proven). We get a "pattern-matching is not exhaustive" warning *)
(* here, but we have already checked that new_hyps is non-empty. *)
(* (+) prim_thm is a trivial theorem that proves the subgoal corresponding *)
(* to prim_hyp. *)
(* (+) Instantiate the justification theorem with elim_thm. *)
(* (+) Add prim_hyp to the justification (pretending its a proven subgoal). *)
(* (+) Use a hack to add the eliminated assumption to the proven subgoals so *)
(* that we pass the validity check properly. *)
(* ------------------------------------------------------------------------- *)
let (erulem_tac: (term * term) list -> meta_rule->tactic) =
fun instlist r ((asl,w) as g) ->
let (c,hyps,thm) = inst_meta_rule_vars instlist r (gl_frees g) in
let ins = try ( term_match [] c w )
with Failure _ -> failwith "Rule doesn't match!" in
let new_hyps = map (inst_goal ins) hyps in
let (prems,prim_hyp) =
if (new_hyps = []) then failwith "erule: Not a proper elimination rule: no premises!"
else hd new_hyps in
let avoids = gl_frees g in
let asl,(prim_thm,elim_inst) =
if (prems = [])
then try term_to_asm_match avoids prim_hyp asl with Failure s -> failwith ("erule: " ^ s)
else failwith "erule: Not a proper elimination rule: major premise has assumptions!" in
let (_,prim_hyp)::new_hyps = map (inst_goal elim_inst) new_hyps in
let thm = INSTANTIATE_ALL elim_inst thm in
let create_goal = fun asms (hs,gl) -> (hs@asms,gl) in
let new_goals = map (create_goal asl) new_hyps in
let rec create_dischl =
fun (asms,g) ->
if (asms = []) then []
else ((concl o snd o hd) asms)::(create_dischl ((tl asms),g)) in
let dischls = map create_dischl new_hyps in
let disch_pair = fun i (dischl,thm) -> DISCHL (map (instantiate i) dischl) thm in
let normalfrees = itlist union (map ( fun (_,y) -> frees y ) instlist ) (gl_frees g) in
let mvs = subtract (itlist union (map gl_frees new_goals) []) normalfrees in
(mvs,null_inst),new_goals,fun i l ->
let major_thmi = INSTANTIATE_ALL i prim_thm in
List.fold_left (fun t1 t2 -> PROVE_HYP (INSTANTIATE_ALL i t2) t1) (INSTANTIATE_ALL (compose_insts ins i) thm)
(major_thmi :: map (ADD_HYP major_thmi) (map (disch_pair i) (List.combine dischls l)));;
(* ------------------------------------------------------------------------- *)
(* drulem_tac: ((term * term) list -> meta_rule -> tactic): *)
(* Isabelle's drule as a HOL Light meta_rule tactic. *)
(* Uses rules as shown in "rule". *)
(* Matches the first hypothesis H1 with one of the *)
(* assumptions A1--Am and instantiates accordingly. *)
(* The assumption is removed from the list and the trivial goal is proven *)
(* automatically. *)
(* A "proper" destructio rule H1 is of the form ?- H1 (ie. has no premises) *)
(* The goal A1,A2,...,Am,G ?- C is also added. *)
(* ------------------------------------------------------------------------- *)
(* Same as erulem with a few differences. *)
(* [+] Does not try to match the goal c. *)
(* [+] Adds an extra goal c ?- w after instantiating c. *)
(* [+] The new goal is treated slightly different in the justification. *)
(* It is the one whose premises must be proven so as to get to the final *)
(* goal. So it gets proven using PROVE_HYP by the result of the *)
(* justification on the original rule. *)
(* ------------------------------------------------------------------------- *)
let (drulem_tac: (term * term) list -> meta_rule->tactic) =
fun instlist r ((asl,w) as g) ->
let (c,hyps,thm) = inst_meta_rule_vars instlist r (gl_frees g) in
let (prems,major_prem) =
if (hyps = []) then failwith "drule: Not a proper destruction rule: no premises!"
else hd hyps in
let avoids = gl_frees g in
let asl,(major_thm,elim_inst) =
if (prems = [])
then try term_to_asm_match avoids major_prem asl with Failure s -> failwith ("drule: " ^ s)
else failwith "drule: not a proper destruction rule: major premise has assumptions!" in
let (_,major_asm)::new_hyps = map (inst_goal elim_inst) hyps in
let thm = INSTANTIATE_ALL elim_inst thm in
let create_goal = fun asms (hs,gl) -> (hs@asms,gl) in
let new_goals = (map (create_goal asl) new_hyps) @ [create_goal asl (["",ASSUME (instantiate elim_inst c)],w)] in
let rec create_dischl =
fun (asms,g) ->
if (asms = []) then []
else ((concl o snd o hd) asms)::(create_dischl ((tl asms),g)) in
(* We add an empty discharge list at the end for the extra goal. *)
let dischls = map create_dischl new_hyps @ [[]] in
let disch_pair = fun i (dischl,thm) -> DISCHL (map (instantiate i) dischl) thm in
let normalfrees = itlist union (map ( fun (_,y) -> frees y ) instlist ) (gl_frees g) in
let mvs = subtract (itlist union (map gl_frees new_goals) []) normalfrees in
(mvs,null_inst),new_goals,fun i l ->
let major_thmi = INSTANTIATE_ALL i major_thm in
let l = (major_thmi :: map (ADD_HYP major_thmi) (map (disch_pair i) (List.combine dischls l))) in
PROVE_HYP (List.fold_left (fun t1 t2 -> PROVE_HYP (INSTANTIATE_ALL i t2) t1) (INSTANTIATE_ALL i thm) ((butlast) l)) (last l);;
(* ------------------------------------------------------------------------- *)
(* frulem_tac: ((term * term) list -> meta_rule -> tactic): *)
(* Isabelle's frule as a HOL Light meta_rule tactic. *)
(* Same as drule, but does not remove the matching assumption from the list. *)
(* ------------------------------------------------------------------------- *)
(* Same as drulem only skipping the parts that eat up the assumption and *)
(* re-add it to the proven subgoals. *)
(* ------------------------------------------------------------------------- *)
let (frulem_tac: (term * term) list -> meta_rule->tactic) =
fun instlist r ((asl,w) as g) ->
let (c,hyps,thm) = inst_meta_rule_vars instlist r (gl_frees g) in
let (prems,major_prem) =
if (hyps = []) then failwith "frule: Not a proper destruction rule: no premises!"
else hd hyps in
let avoids = gl_frees g in
let _,(major_thm,elim_inst) =
if (prems = [])
then try term_to_asm_match avoids major_prem asl with Failure s -> failwith ("frule: " ^ s)
else failwith "frule: Not a proper destruction rule: major premise has assumptions!" in
let (_,major_asm)::new_hyps = map (inst_goal elim_inst) hyps in
let thm = INSTANTIATE_ALL elim_inst thm in
let create_goal = fun asms (hs,gl) -> (hs@asms,gl) in
let new_goals = (map (create_goal asl) new_hyps) @ [create_goal asl (["",ASSUME (instantiate elim_inst c)],w)] in
let rec create_dischl =
fun (asms,g) ->
if (asms = []) then []
else ((concl o snd o hd) asms)::(create_dischl ((tl asms),g)) in
let dischls = map create_dischl new_hyps @ [[]] in
let disch_pair = fun i (dischl,thm) -> DISCHL (map (instantiate i) dischl) thm in
let normalfrees = itlist union (map ( fun (_,y) -> frees y ) instlist ) (gl_frees g) in
let mvs = subtract (itlist union (map gl_frees new_goals) []) normalfrees in
(mvs,null_inst),new_goals,fun i l ->
let major_thmi = INSTANTIATE_ALL i major_thm in
let l = (major_thmi :: ((map (disch_pair i)) o (List.combine dischls)) l) in
PROVE_HYP (List.fold_left (fun t1 t2 -> PROVE_HYP (INSTANTIATE_ALL i t2) t1) (INSTANTIATE_ALL i thm) ((butlast) l)) (last l);;
(* ------------------------------------------------------------------------- *)
(* cutm_tac: ((term * term) list -> meta_rule -> tactic): *)
(* Isabelle's cut_tac as a HOL Light meta_rule tactic. *)
(* Inserts a theorem in the assumptions. *)
(* ------------------------------------------------------------------------- *)
(* (+) WARNING: It does not introduce metavariables like the other tactics *)
(* do! In the TODO list... *)
(* ------------------------------------------------------------------------- *)
let (cutm_tac: (term * term) list -> meta_rule->tactic) =
fun instlist r g ->
let (_,_,thm) = inst_meta_rule_vars instlist r (gl_frees g) in
(ASSUME_TAC thm) g;;
(* ------------------------------------------------------------------------- *)
(* erulenm_tac : (term * term) list -> int -> meta_rule->tactic) *)
(* drulenm_tac : (term * term) list -> int -> meta_rule->tactic) *)
(* frulenm_tac : (term * term) list -> int -> meta_rule->tactic) *)
(* Identical to their counterparts, the only difference being that they try *)
(* to match a particular assumption given by number. *)
(* ------------------------------------------------------------------------- *)
let (erulenm_tac: (term * term) list -> int -> meta_rule->tactic) =
fun instlist n r ((asl,w) as g) ->
let (c,hyps,thm) = inst_meta_rule_vars instlist r (gl_frees g) in
let ins = try ( term_match [] c w )
with Failure _ -> failwith "Rule doesn't match!" in
let new_hyps = map (inst_goal ins) hyps in
let (prems,prim_hyp) =
if (new_hyps = []) then failwith "erule: Not a proper elimination rule: no premises!"
else hd new_hyps in
let avoids = gl_frees g in
let asl,(prim_thm,elim_inst) =
if (prems = [])
then try term_to_asm_n_match avoids prim_hyp (rev asl) n with Failure s -> failwith ("erule: " ^ s)
else failwith "erule: Not a proper elimination rule: major premise has assumptions!" in
let (_,prim_hyp)::new_hyps = map (inst_goal elim_inst) new_hyps in
let thm = INSTANTIATE_ALL elim_inst thm in
let create_goal = fun asms (hs,gl) -> (hs@asms,gl) in
let new_goals = map (create_goal asl) new_hyps in
let rec create_dischl =
fun (asms,g) ->
if (asms = []) then []
else ((concl o snd o hd) asms)::(create_dischl ((tl asms),g)) in
let dischls = map create_dischl new_hyps in
let disch_pair = fun i (dischl,thm) -> DISCHL (map (instantiate i) dischl) thm in
let normalfrees = itlist union (map ( fun (_,y) -> frees y ) instlist ) (gl_frees g) in
let mvs = subtract (itlist union (map gl_frees new_goals) []) normalfrees in
(mvs,null_inst),new_goals,fun i l ->
let major_thmi = INSTANTIATE_ALL i prim_thm in
List.fold_left (fun t1 t2 -> PROVE_HYP (INSTANTIATE_ALL i t2) t1) (INSTANTIATE_ALL (compose_insts ins i) thm)
(major_thmi :: map (ADD_HYP major_thmi) (map (disch_pair i) (List.combine dischls l)));;
let (drulenm_tac: (term * term) list -> int -> meta_rule->tactic) =
fun instlist n r ((asl,w) as g) ->
let (c,hyps,thm) = inst_meta_rule_vars instlist r (gl_frees g) in
let (prems,major_prem) =
if (hyps = []) then failwith "drule: Not a proper destruction rule: no premises!"
else hd hyps in
let avoids = gl_frees g in
let asl,(major_thm,elim_inst) =
if (prems = [])
then try term_to_asm_n_match avoids major_prem (rev asl) n with Failure s -> failwith ("drule: " ^ s)
else failwith "drule: not a proper destruction rule: major premise has assumptions!" in
let (_,major_asm)::new_hyps = map (inst_goal elim_inst) hyps in
let thm = INSTANTIATE_ALL elim_inst thm in
let create_goal = fun asms (hs,gl) -> (hs@asms,gl) in
let new_goals = (map (create_goal asl) new_hyps) @ [create_goal asl (["",ASSUME (instantiate elim_inst c)],w)] in
let rec create_dischl =
fun (asms,g) ->
if (asms = []) then []
else ((concl o snd o hd) asms)::(create_dischl ((tl asms),g)) in
(* We add an empty discharge list at the end for the extra goal. *)
let dischls = map create_dischl new_hyps @ [[]] in
let disch_pair = fun i (dischl,thm) -> DISCHL (map (instantiate i) dischl) thm in
let normalfrees = itlist union (map ( fun (_,y) -> frees y ) instlist ) (gl_frees g) in
let mvs = subtract (itlist union (map gl_frees new_goals) []) normalfrees in
(mvs,null_inst),new_goals,fun i l ->
let major_thmi = INSTANTIATE_ALL i major_thm in
let l = (major_thmi :: map (ADD_HYP major_thmi) (map (disch_pair i) (List.combine dischls l))) in
PROVE_HYP (List.fold_left (fun t1 t2 -> PROVE_HYP (INSTANTIATE_ALL i t2) t1) (INSTANTIATE_ALL i thm) ((butlast) l)) (last l);;
let (frulenm_tac: (term * term) list -> int -> meta_rule->tactic) =
fun instlist n r ((asl,w) as g) ->
let (c,hyps,thm) = inst_meta_rule_vars instlist r (gl_frees g) in
let (prems,major_prem) =
if (hyps = []) then failwith "frule: Not a proper destruction rule: no premises!"
else hd hyps in
let avoids = gl_frees g in
let _,(major_thm,elim_inst) =
if (prems = [])
then try term_to_asm_n_match avoids major_prem (rev asl) n with Failure s -> failwith ("frule: " ^ s)
else failwith "frule: Not a proper destruction rule: major premise has assumptions!" in
let (_,major_asm)::new_hyps = map (inst_goal elim_inst) hyps in
let thm = INSTANTIATE_ALL elim_inst thm in
let create_goal = fun asms (hs,gl) -> (hs@asms,gl) in
let new_goals = (map (create_goal asl) new_hyps) @ [create_goal asl (["",ASSUME (instantiate elim_inst c)],w)] in
let rec create_dischl =
fun (asms,g) ->
if (asms = []) then []
else ((concl o snd o hd) asms)::(create_dischl ((tl asms),g)) in
let dischls = map create_dischl new_hyps @ [[]] in
let disch_pair = fun i (dischl,thm) -> DISCHL (map (instantiate i) dischl) thm in
let normalfrees = itlist union (map ( fun (_,y) -> frees y ) instlist ) (gl_frees g) in
let mvs = subtract (itlist union (map gl_frees new_goals) []) normalfrees in
(mvs,null_inst),new_goals,fun i l ->
let major_thmi = INSTANTIATE_ALL i major_thm in
let l = (major_thmi :: ((map (disch_pair i)) o (List.combine dischls)) l) in
PROVE_HYP (List.fold_left (fun t1 t2 -> PROVE_HYP (INSTANTIATE_ALL i t2) t1) (INSTANTIATE_ALL i thm) ((butlast) l)) (last l);;
(* ------------------------------------------------------------------------- *)
(* Xrulem versions for empty instlist. *)
(* ------------------------------------------------------------------------- *)
let rulem: meta_rule -> tactic = rulem_tac [];;
let erulem: meta_rule -> tactic = erulem_tac [];;
let drulem: meta_rule -> tactic = drulem_tac [];;
let frulem: meta_rule -> tactic = frulem_tac [];;
let erulenm: int -> meta_rule -> tactic = erulenm_tac [];;
let drulenm: int -> meta_rule -> tactic = drulenm_tac [];;
let frulenm: int -> meta_rule -> tactic = frulenm_tac [];;
(* For consistency with HOL Light capitalized tactics: *)
let RULEM,ERULEM,DRULEM,FRULEM = rulem,erulem,drulem,frulem;;
let ERULENM,DRULENM,FRULENM = erulenm,drulenm,frulenm;;
(* ------------------------------------------------------------------------- *)
(* Xrule and Xrule_tac using arbitrary inference rules in the form of thms. *)
(* (see mk_meta_rule and meta_rule type) *)
(* ------------------------------------------------------------------------- *)
let rule_tac: (term * term) list -> thm -> tactic =
fun instlist thm ->
rulem_tac instlist (mk_meta_rule thm);;
let erule_tac: (term * term) list -> thm -> tactic =
fun instlist thm ->
erulem_tac instlist (mk_meta_rule thm);;
let drule_tac: (term * term) list -> thm -> tactic =
fun instlist thm ->
drulem_tac instlist (mk_meta_rule thm);;
let frule_tac: (term * term) list -> thm -> tactic =
fun instlist thm ->
frulem_tac instlist (mk_meta_rule thm);;
let cut_tac: (term * term) list -> thm -> tactic =
fun instlist thm ->
cutm_tac instlist (mk_meta_rule thm);;
let RULE_TAC,ERULE_TAC,DRULE_TAC,FRULE_TAC,CUT_TAC = rule_tac,erule_tac,drule_tac,frule_tac,cut_tac;;
let erulen_tac: (term * term) list -> int -> thm -> tactic =
fun instlist n thm ->
erulenm_tac instlist n (mk_meta_rule thm);;
let drulen_tac: (term * term) list -> int -> thm -> tactic =
fun instlist n thm ->
drulenm_tac instlist n (mk_meta_rule thm);;
let frulen_tac: (term * term) list -> int -> thm -> tactic =
fun instlist n thm ->
frulenm_tac instlist n (mk_meta_rule thm);;
let ERULEN_TAC,DRULEN_TAC,FRULEN_TAC = erulen_tac,drulen_tac,frulen_tac;;
let rule: (thm -> tactic) = rule_tac [];;
let erule: (thm -> tactic) = erule_tac [];;
let drule: (thm -> tactic) = drule_tac [];;
let frule: (thm -> tactic) = frule_tac [];;
let RULE,ERULE,DRULE,FRULE = rule,erule,drule,frule;;
let erulen: (int -> thm -> tactic) = erulen_tac [];;
let drulen: (int -> thm -> tactic) = drulen_tac [];;
let frulen: (int -> thm -> tactic) = frulen_tac [];;
let ERULEN,DRULEN,FRULEN = erulen,drulen,frulen;;