aboutsummaryrefslogtreecommitdiffhomepage
path: root/tactics/tactics.ml
diff options
context:
space:
mode:
Diffstat (limited to 'tactics/tactics.ml')
-rw-r--r--tactics/tactics.ml831
1 files changed, 247 insertions, 584 deletions
diff --git a/tactics/tactics.ml b/tactics/tactics.ml
index 2285850c0..f154ef372 100644
--- a/tactics/tactics.ml
+++ b/tactics/tactics.ml
@@ -24,16 +24,19 @@ open Declare
open Evd
open Pfedit
open Tacred
+open Rawterm
open Tacmach
open Proof_trees
open Proof_type
open Logic
open Evar_refiner
open Clenv
+open Refiner
open Tacticals
open Hipattern
open Coqlib
open Nametab
+open Tacexpr
exception Bound
@@ -54,12 +57,14 @@ let rec nb_prod x =
(* General functions *)
(****************************************)
+(*
let get_pairs_from_bindings =
let pair_from_binding = function
| [(Bindings binds)] -> binds
| _ -> error "not a binding list!"
in
List.map pair_from_binding
+*)
let string_of_inductive c =
try match kind_of_term c with
@@ -85,8 +90,10 @@ let rec head_constr_bound t l =
let head_constr c =
try head_constr_bound c [] with Bound -> error "Bound head variable"
+(*
let bad_tactic_args s l =
raise (RefinerError (BadTacticArgs (s,l)))
+*)
(******************************************)
(* Primitive tactics *)
@@ -100,54 +107,27 @@ let refine = Tacmach.refine
let convert_concl = Tacmach.convert_concl
let convert_hyp = Tacmach.convert_hyp
let thin = Tacmach.thin
-let thin_body = Tacmach.thin_body
-let move_hyp = Tacmach.move_hyp
+let thin_body = Tacmach.thin_body
+
+(* Moving hypotheses *)
+let move_hyp = Tacmach.move_hyp
+
+(* Renaming hypotheses *)
let rename_hyp = Tacmach.rename_hyp
-let mutual_fix = Tacmach.mutual_fix
-let fix f n = mutual_fix f n []
-
-let fix_noname n =
- let id = Pfedit.get_current_proof_name () in
- fix id n
-
-let dyn_mutual_fix argsl gl =
- match argsl with
- | [Integer n] -> fix_noname n gl
- | [Identifier id;Integer n] -> fix id n gl
- | ((Identifier id)::(Integer n)::lfix) ->
- let rec decomp lar = function
- | (Fixexp (id,n,ar)::rest) ->
- decomp ((id,n,pf_interp_constr gl ar)::lar) rest
- | [] -> (List.rev lar)
- | _ -> bad_tactic_args "mutual_fix" argsl
- in
- let lar = decomp [] lfix in
- mutual_fix id n lar gl
- | l -> bad_tactic_args "mutual_fix" l
+(* Refine as a fixpoint *)
+let mutual_fix = Tacmach.mutual_fix
+let fix ido n = match ido with
+ | None -> mutual_fix (Pfedit.get_current_proof_name ()) n []
+ | Some id -> mutual_fix id n []
+
+(* Refine as a cofixpoint *)
let mutual_cofix = Tacmach.mutual_cofix
-let cofix f = mutual_cofix f []
-
-let cofix_noname n =
- let id = Pfedit.get_current_proof_name () in
- cofix id n
-
-let dyn_mutual_cofix argsl gl =
- match argsl with
- | [] -> cofix_noname gl
- | [(Identifier id)] -> cofix id gl
- | ((Identifier id)::lcofix) ->
- let rec decomp lar = function
- | (Cofixexp (id,ar)::rest) ->
- decomp ((id,pf_interp_constr gl ar)::lar) rest
- | [] -> List.rev lar
- | _ -> bad_tactic_args "mutual_cofix" argsl
- in
- let lar = decomp [] lcofix in
- mutual_cofix id lar gl
- | l -> bad_tactic_args "mutual_cofix" l
+let cofix = function
+ | None -> mutual_cofix (Pfedit.get_current_proof_name ()) []
+ | Some id -> mutual_cofix id []
(**************************************************************)
(* Reduction and conversion tactics *)
@@ -213,7 +193,7 @@ let change_option t = function
| Some id -> reduct_in_hyp (change_hyp_and_check t) id
| None -> reduct_in_concl (change_concl_and_check t)
-(* Pour usage interne (le niveau User est pris en compte par dyn_reduce) *)
+(* Pour usage interne (le niveau User est pris en compte par reduce) *)
let red_in_concl = reduct_in_concl red_product
let red_in_hyp = reduct_in_hyp red_product
let red_option = reduct_option red_product
@@ -231,12 +211,7 @@ let unfold_in_hyp loccname = reduct_in_hyp (unfoldn loccname)
let unfold_option loccname = reduct_option (unfoldn loccname)
let pattern_option l = reduct_option (pattern_occs l)
-let dyn_change = function
- | [Constr c; Clause cl] ->
- (fun goal ->
-(* let c = Astterm.interp_type (project goal) (pf_env goal) com in*)
- in_combinator (change_in_concl c) (change_in_hyp c) cl goal)
- | l -> bad_tactic_args "change" l
+let change c = in_combinator (change_in_concl c) (change_in_hyp c)
(* A function which reduces accordingly to a reduction expression,
as the command Eval does. *)
@@ -244,10 +219,6 @@ let dyn_change = function
let reduce redexp cl goal =
redin_combinator (reduction_of_redexp redexp) cl goal
-let dyn_reduce = function
- | [Redexp redexp; Clause cl] -> (fun goal -> reduce redexp cl goal)
- | l -> bad_tactic_args "reduce" l
-
(* Unfolding occurrences of a constant *)
let unfold_constr = function
@@ -360,93 +331,59 @@ let intros_replacing ids gls =
(* User-level introduction tactics *)
-let dyn_intro = function
- | [] -> intro_gen (IntroAvoid []) None true
- | [Identifier id] -> intro_gen (IntroMustBe id) None true
- | l -> bad_tactic_args "intro" l
-
-let dyn_intro_move = function
- | [Identifier id2] -> intro_gen (IntroAvoid []) (Some id2) true
- | [Identifier id; Identifier id2] ->
- intro_gen (IntroMustBe id) (Some id2) true
- | l -> bad_tactic_args "intro_move" l
-
-let rec intros_until s g =
- match pf_lookup_name_as_renamed (pf_env g) (pf_concl g) s with
- | Some depth -> tclDO depth intro g
- | None ->
- try
- ((tclTHEN (reduce (Red true) []) (intros_until s)) g)
- with Redelimination ->
- errorlabstrm "Intros"
- (str ("No hypothesis "^(string_of_id s)^" in current goal") ++
- str " even after head-reduction")
-
-let rec intros_until_n_gen red n g =
- match pf_lookup_index_as_renamed (pf_env g) (pf_concl g) n with
- | Some depth -> tclDO depth intro g
+let intro_move idopt idopt' = match idopt with
+ | None -> intro_gen (IntroAvoid []) idopt' true
+ | Some id -> intro_gen (IntroMustBe id) idopt' true
+
+let pf_lookup_hypothesis_as_renamed env ccl = function
+ | AnonHyp n -> pf_lookup_index_as_renamed env ccl n
+ | NamedHyp id -> pf_lookup_name_as_renamed env ccl id
+
+let pf_lookup_hypothesis_as_renamed_gen red h gl =
+ let env = pf_env gl in
+ let rec aux ccl =
+ match pf_lookup_hypothesis_as_renamed env ccl h with
+ | None when red -> aux (reduction_of_redexp (Red true) env Evd.empty ccl)
+ | x -> x
+ in
+ try aux (pf_concl gl)
+ with Redelimination -> None
+
+let is_quantified_hypothesis id g =
+ match pf_lookup_hypothesis_as_renamed_gen true (NamedHyp id) g with
+ | Some _ -> true
+ | None -> false
+
+let msg_quantified_hypothesis = function
+ | NamedHyp id ->
+ str "hypothesis " ++ pr_id id
+ | AnonHyp n ->
+ int n ++ str (match n with 1 -> "st" | 2 -> "nd" | _ -> "th") ++
+ str " non dependent hypothesis"
+
+let depth_of_quantified_hypothesis red h gl =
+ match pf_lookup_hypothesis_as_renamed_gen red h gl with
+ | Some depth -> depth
| None ->
- if red then
- try
- ((tclTHEN (reduce (Red true) []) (intros_until_n_gen red n)) g)
- with Redelimination ->
- errorlabstrm "Intros"
- (str ("No "^(string_of_int n)) ++
- str (match n with 1 -> "st" | 2 -> "nd" | _ -> "th") ++
- str " non dependent hypothesis in current goal" ++
- str " even after head-reduction")
- else
- errorlabstrm "Intros" (str "No such hypothesis in current goal")
+ errorlabstrm "lookup_quantified_hypothesis"
+ (str "No " ++ msg_quantified_hypothesis h ++
+ str " in current goal" ++
+ if red then str " even after head-reduction" else mt ())
+
+let intros_until_gen red h g =
+ tclDO (depth_of_quantified_hypothesis red h g) intro g
+let intros_until_id id = intros_until_gen true (NamedHyp id)
+let intros_until_n_gen red n = intros_until_gen red (AnonHyp n)
+
+let intros_until = intros_until_gen true
let intros_until_n = intros_until_n_gen true
let intros_until_n_wored = intros_until_n_gen false
-let dyn_intros_until = function
- | [Identifier id] -> intros_until id
- | [Integer n] -> intros_until_n n
- | l -> bad_tactic_args "Intros until" l
-
-let tactic_try_intros_until tac = function
- | Identifier id ->
- tclTHEN (tclTRY (intros_until id)) (tac id)
- | Integer n ->
- tclTHEN (intros_until_n n)
- (fun gl -> let id,_,_ = pf_last_hyp gl in tac id gl)
- | c -> bad_tactic_args "tactic_try_intros_until" [c]
-
-let hide_ident_or_numarg_tactic s tac =
- let tacfun = function
- | [Identifier id] -> tclTHEN (tclTRY (intros_until id)) (tac id)
- | [Integer n] ->
- tclTHEN (intros_until_n n)
- (fun gl -> let id,_,_ = pf_last_hyp gl in tac id gl)
- | _ -> assert false in
- add_tactic s tacfun;
- fun id -> vernac_tactic(s,[Identifier id])
-
-
-(* Obsolete, remplace par intros_unitl_n ?
-let intros_do n g =
- let depth =
- let rec lookup all nodep c = match kind_of_term c with
- | Prod (name,_,c') ->
- (match name with
- | Name(s') ->
- if dependent (mkRel 1) c' then
- lookup (all+1) nodep c'
- else if nodep = n then
- all
- else
- lookup (all+1) (nodep+1) c'
- | Anonymous ->
- if nodep=n then all else lookup (all+1) (nodep+1) c')
- | Cast (c,_) -> lookup all nodep c
- | _ -> error "No such hypothesis in current goal"
- in
- lookup 1 1 (pf_concl g)
- in
- tclDO depth intro g
-*)
+let try_intros_until tac = function
+ | NamedHyp id -> tclTHEN (tclTRY (intros_until_id id)) (tac id)
+ | AnonHyp n -> tclTHEN (intros_until_n n) (onLastHyp tac)
+
let rec intros_move = function
| [] -> tclIDTAC
| (hyp,destopt) :: rest ->
@@ -508,8 +445,7 @@ let bring_hyps hyps =
(* Resolution with missing arguments *)
-
-let apply_with_bindings (c,lbind) gl =
+let apply_with_bindings (c,lbind) gl =
let apply =
match kind_of_term c with
| Lambda _ -> res_pf_cast
@@ -539,11 +475,11 @@ let apply_with_bindings (c,lbind) gl =
apply kONT clause gl
-let apply c = apply_with_bindings (c,[])
-let apply_com = tactic_com (fun c -> apply_with_bindings (c,[]))
+let apply c = apply_with_bindings (c,NoBindings)
+let apply_com = tactic_com (fun c -> apply_with_bindings (c,NoBindings))
let apply_list = function
- | c::l -> apply_with_bindings (c,List.map (fun com ->(Com,com)) l)
+ | c::l -> apply_with_bindings (c,ImplicitBindings l)
| _ -> assert false
(* Resolution with no reduction on the type *)
@@ -557,85 +493,68 @@ let apply_without_reduce_com = tactic_com apply_without_reduce
let refinew_scheme kONT clause gl = res_pf kONT clause gl
-let dyn_apply l =
- match l with
- | [Command com; Bindings binds] ->
- tactic_com_bind_list apply_with_bindings (com,binds)
- | [Constr c; Cbindings binds] ->
- apply_with_bindings (c,binds)
- | l ->
- bad_tactic_args "apply" l
+(* A useful resolution tactic which, if c:A->B, transforms |- C into
+ |- B -> C and |- A (which is realized by Cut B;[Idtac|Apply c]
-(* A useful resolution tactic, equivalent to Cut type_of_c;[Idtac|Apply c] *)
+ -------------------
+ Gamma |- c : A -> B Gamma |- ?2 : A
+ ----------------------------------------
+ Gamma |- B Gamma |- ?1 : B -> C
+ -----------------------------------------------------
+ Gamma |- ? : C
+ *)
let cut_and_apply c gl =
let goal_constr = pf_concl gl in
match kind_of_term (pf_hnf_constr gl (pf_type_of gl c)) with
| Prod (_,c1,c2) when not (dependent (mkRel 1) c2) ->
- tclTHENS
- (apply_type (mkProd (Anonymous,c2,goal_constr))
- [mkMeta (new_meta())])
- [tclIDTAC;apply_term c [mkMeta (new_meta())]] gl
+ tclTHENLAST
+ (apply_type (mkProd (Anonymous,c2,goal_constr)) [mkMeta(new_meta())])
+ (apply_term c [mkMeta (new_meta())]) gl
| _ -> error "Imp_elim needs a non-dependent product"
-let dyn_cut_and_apply = function
- | [Command com] -> tactic_com cut_and_apply com
- | [Constr c] -> cut_and_apply c
- | l -> bad_tactic_args "cut_and_apply" l
-
(**************************)
(* Cut tactics *)
(**************************)
-let true_cut id c gl =
- match kind_of_term (hnf_type_of gl c) with
- | Sort _ -> internal_cut id c gl
- | _ -> error "Not a proposition or a type"
-
-let true_cut_anon c gl =
+let true_cut idopt c gl =
match kind_of_term (hnf_type_of gl c) with
| Sort s ->
- let d = match s with Prop _ -> "H" | Type _ -> "X" in
- let id = next_name_away_with_default d Anonymous (pf_ids_of_hyps gl) in
- internal_cut id c gl
+ let id =
+ match idopt with
+ | None ->
+ let d = match s with Prop _ -> "H" | Type _ -> "X" in
+ next_name_away_with_default d Anonymous (pf_ids_of_hyps gl)
+ | Some id -> id
+ in
+ internal_cut id c gl
| _ -> error "Not a proposition or a type"
-let dyn_true_cut = function
- | [Command com] -> tactic_com_sort true_cut_anon com
- | [Constr c] -> true_cut_anon c
- | [Command com; Identifier id] -> tactic_com_sort (true_cut id) com
- | [Constr c; Identifier id] -> true_cut id c
- | l -> bad_tactic_args "true_cut" l
-
let cut c gl =
match kind_of_term (hnf_type_of gl c) with
| Sort _ ->
let id=next_name_away_with_default "H" Anonymous (pf_ids_of_hyps gl) in
let t = mkProd (Anonymous, c, pf_concl gl) in
- tclTHENS
+ tclTHENFIRST
(internal_cut_rev id c)
- [tclTHEN (apply_type t [mkVar id]) (thin [id]);
- tclIDTAC] gl
+ (tclTHEN (apply_type t [mkVar id]) (thin [id]))
+ gl
| _ -> error "Not a proposition or a type"
-let dyn_cut = function
- | [Command com] -> tactic_com_sort cut com
- | [Constr c] -> cut c
- | l -> bad_tactic_args "cut" l
-
-let cut_intro t = (tclTHENS (cut t) [intro;tclIDTAC])
+let cut_intro t = tclTHENFIRST (cut t) intro
let cut_replacing id t =
- (tclTHENS (cut t)
- [(tclORELSE (intro_replacing id)
- (tclORELSE (intro_erasing id)
- (intro_using id)));
- tclIDTAC])
+ tclTHENFIRST
+ (cut t)
+ (tclORELSE
+ (intro_replacing id)
+ (tclORELSE (intro_erasing id)
+ (intro_using id)))
let cut_in_parallel l =
let rec prec = function
| [] -> tclIDTAC
- | h::t -> (tclTHENS (cut h) ([prec t;tclIDTAC]))
+ | h::t -> tclTHENFIRST (cut h) (prec t)
in
prec (List.rev l)
@@ -693,13 +612,6 @@ let generalize lconstr gl =
let newcl = List.fold_right (generalize_goal gl) lconstr (pf_concl gl) in
apply_type newcl lconstr gl
-let dyn_generalize =
- fun argsl -> generalize (List.map Tacinterp.constr_of_Constr argsl)
-
-let dyn_generalize_dep = function
- | [Constr csr] -> generalize_dep csr
- | l -> bad_tactic_args "dyn_generalize_dep" l
-
(* Faudra-t-il une version avec plusieurs args de generalize_dep ?
Cela peut-être troublant de faire "Generalize Dependent H n" dans
"n:nat; H:n=n |- P(n)" et d'échouer parce que H a disparu après la
@@ -736,21 +648,35 @@ let quantify lconstr =
the left of each x1, ...).
*)
-let letin_abstract id c (occ_ccl,occ_hyps) gl =
- let everywhere = (occ_ccl = None) & (occ_hyps = []) in
+let occurrences_of_hyp id = function
+ | None, [] -> (* Everywhere *) Some []
+ | _, occ_hyps -> try Some (List.assoc id occ_hyps) with Not_found -> None
+
+let occurrences_of_goal = function
+ | None, [] -> (* Everywhere *) Some []
+ | Some gocc as x, _ -> x
+ | None, _ -> None
+
+let everywhere (occ_ccl,occ_hyps) = (occ_ccl = None) & (occ_hyps = [])
+
+let letin_abstract id c occs gl =
let env = pf_env gl in
let compute_dependency _ (hyp,_,_ as d) ctxt =
let d' =
try
- let occ = if everywhere then [] else List.assoc hyp occ_hyps in
- let newdecl = subst_term_occ_decl env occ c d in
- if d = newdecl then
- if not everywhere then raise (RefinerError (DoesNotOccurIn (c,hyp)))
- else raise Not_found
- else
- (subst1_decl (mkVar id) newdecl, true)
- with Not_found ->
- (d,List.exists (fun((id,_,_),dep) -> dep && occur_var_in_decl env id d) ctxt)
+ match occurrences_of_hyp hyp occs with
+ | None -> raise Not_found
+ | Some occ ->
+ let newdecl = subst_term_occ_decl env occ c d in
+ if d = newdecl then
+ if not (everywhere occs)
+ then raise (RefinerError (DoesNotOccurIn (c,hyp)))
+ else raise Not_found
+ else
+ (subst1_decl (mkVar id) newdecl, true)
+ with Not_found ->
+ (d,List.exists
+ (fun ((id,_,_),dep) -> dep && occur_var_in_decl env id d) ctxt)
in d'::ctxt
in
let ctxt' = fold_named_context compute_dependency env ~init:[] in
@@ -758,27 +684,7 @@ let letin_abstract id c (occ_ccl,occ_hyps) gl =
if b then ((d::depdecls,(hyp,lhyp)::marks), lhyp)
else (accu, Some hyp) in
let (depdecls,marks),_ = List.fold_left compute_marks (([],[]),None) ctxt' in
-(*
- let abstract ((depdecls,marks as accu),lhyp) (hyp,_,_ as d) =
- try
- let occ = if everywhere then [] else List.assoc hyp occ_hyps in
- let newdecl = subst_term_occ_decl env occ c d in
- if d = newdecl then
- if not everywhere then raise (RefinerError (DoesNotOccurIn (c,hyp)))
- else
- if List.exists (fun (id,_,_) -> occur_var id d)
- (accu, Some hyp)
- else
- let newdecl = subst1_decl (mkVar id) newdecl in
- ((newdecl::depdecls,(hyp,lhyp)::marks), lhyp)
- with Not_found ->
- (accu, Some hyp)
- in
- let (depdecls,marks),_ =
- fold_named_context_reverse abstract ~init:(([],[]),None) env in(* *)
-*)
- let occ_ccl = if everywhere then Some [] else occ_ccl in
- let ccl = match occ_ccl with
+ let ccl = match occurrences_of_goal occs with
| None -> pf_concl gl
| Some occ -> subst1 (mkVar id) (subst_term_occ env occ c (pf_concl gl))
in
@@ -810,7 +716,7 @@ let letin_tac with_eq name c occs gl =
if with_eq then tclIDTAC else thin_body [id];
intros_move marks ] gl
-let check_hypotheses_occurrences_list env occl =
+let check_hypotheses_occurrences_list env (_,occl) =
let rec check acc = function
| (hyp,_) :: rest ->
if List.mem hyp acc then
@@ -821,27 +727,9 @@ let check_hypotheses_occurrences_list env occl =
| [] -> ()
in check [] occl
-let dyn_lettac args gl = match args with
- | [Identifier id; Command com; Letpatterns (o,l)] ->
- check_hypotheses_occurrences_list (pf_env gl) l;
- letin_tac true (Name id) (pf_interp_constr gl com) (o,l) gl
- | [Identifier id; Constr c; Letpatterns (o,l)] ->
- check_hypotheses_occurrences_list (pf_env gl) l;
- letin_tac true (Name id) c (o,l) gl
- | l -> bad_tactic_args "letin" l
-
let nowhere = (Some [],[])
-let dyn_forward args gl = match args with
- | [Quoted_string s; Command com; Identifier id] ->
- letin_tac (s="KeepBody") (Name id) (pf_interp_constr gl com) nowhere gl
- | [Quoted_string s; Constr c; Identifier id] ->
- letin_tac (s="KeepBody") (Name id) c nowhere gl
- | [Quoted_string s; Constr c] ->
- letin_tac (s="KeepBody") Anonymous c nowhere gl
- | [Quoted_string s; Command c] ->
- letin_tac (s="KeepBody") Anonymous (pf_interp_constr gl c) nowhere gl
- | l -> bad_tactic_args "forward" l
+let forward b na c = letin_tac b na c nowhere
(********************************************************************)
(* Exact tactics *)
@@ -857,23 +745,10 @@ let exact_check c gl =
let exact_no_check = refine
-let dyn_exact_no_check cc gl = match cc with
- | [Constr c] -> exact_no_check c gl
- | [Command com] ->
- let evc = (project gl) in
- let concl = (pf_concl gl) in
- let c = Astterm.interp_casted_constr evc (pf_env gl) com concl in
- refine c gl
- | l -> bad_tactic_args "exact_no_check" l
-
-let dyn_exact_check cc gl = match cc with
- | [Constr c] -> exact_check c gl
- | [Command com] ->
- let evc = (project gl) in
- let concl = (pf_concl gl) in
- let c = Astterm.interp_casted_constr evc (pf_env gl) com concl in
- refine c gl
- | l -> bad_tactic_args "exact_check" l
+let exact_proof c gl =
+ (* on experimente la synthese d'ise dans exact *)
+ let c = Astterm.interp_casted_constr (project gl) (pf_env gl) c (pf_concl gl)
+ in refine c gl
let (assumption : tactic) = fun gl ->
let concl = pf_concl gl in
@@ -885,11 +760,6 @@ let (assumption : tactic) = fun gl ->
in
arec (pf_hyps gl)
-let dyn_assumption = function
- | [] -> assumption
- | l -> bad_tactic_args "assumption" l
-
-
(*****************************************************************)
(* Modification of a local context *)
(*****************************************************************)
@@ -899,22 +769,10 @@ let dyn_assumption = function
* subsequently used in other hypotheses or in the conclusion of the
* goal. *)
-let clear ids gl = thin ids gl
-let dyn_clear = function
- | [Clause ids] ->
- if ids=[] then tclIDTAC
- else
- let out = function InHyp id -> id | _ -> assert false in
- clear (List.map out ids)
- | l -> bad_tactic_args "clear" l
+let clear ids gl = (* avant seul dyn_clear n'echouait pas en [] *)
+ if ids=[] then tclIDTAC gl else thin ids gl
let clear_body = thin_body
-let dyn_clear_body = function
- | [Clause ids] ->
- let out = function InHyp id -> id | _ -> assert false in
- clear_body (List.map out ids)
- | l -> bad_tactic_args "clear_body" l
-
(* Takes a list of booleans, and introduces all the variables
* quantified in the goal which are associated with a value
@@ -940,44 +798,10 @@ let new_hyp mopt c lbind g =
| Some m -> if m < nargs then list_firstn m tstack else tstack
| None -> tstack)
in
- (tclTHENL (tclTHEN (kONT clause.hook)
+ (tclTHENLAST (tclTHEN (kONT clause.hook)
(cut (pf_type_of g cut_pf)))
((tclORELSE (apply cut_pf) (exact_no_check cut_pf)))) g
-let dyn_new_hyp argsl gl =
- match argsl with
- | [Integer n; Command com; Bindings binds] ->
- tactic_bind_list
- (new_hyp (Some n)
- (pf_interp_constr gl com))
- binds gl
- | [Command com; Bindings binds] ->
- tactic_bind_list
- (new_hyp None
- (pf_interp_constr gl com))
- binds gl
- | [Integer n; Constr c; Cbindings binds] ->
- new_hyp (Some n) c binds gl
- | [Constr c; Cbindings binds] ->
- new_hyp None c binds gl
- | l -> bad_tactic_args "new_hyp" l
-
-(* Moving hypotheses *)
-
-let dyn_move = function
- | [Identifier idfrom; Identifier idto] -> move_hyp false idfrom idto
- | l -> bad_tactic_args "move" l
-
-let dyn_move_dep = function
- | [Identifier idfrom; Identifier idto] -> move_hyp true idfrom idto
- | l -> bad_tactic_args "move_dep" l
-
-(* Renaming hypotheses *)
-
-let dyn_rename = function
- | [Identifier idfrom; Identifier idto] -> rename_hyp idfrom idto
- | l -> bad_tactic_args "rename" l
-
(************************)
(* Introduction tactics *)
(************************)
@@ -1002,63 +826,28 @@ let constructor_tac boundopt i lbind gl =
let one_constructor i = constructor_tac None i
-let any_constructor gl =
- let cl = pf_concl gl in
- let (mind,redcl) = pf_reduce_to_quantified_ind gl cl in
- let nconstr =
- Array.length (snd (Global.lookup_inductive mind)).mind_consnames
- and sigma = project gl in
- if nconstr = 0 then error "The type has no constructors";
- tclFIRST (List.map (fun i -> one_constructor i [])
- (interval 1 nconstr)) gl
-
(* Try to apply the constructor of the inductive definition followed by
a tactic t given as an argument.
Should be generalize in Constructor (Fun c : I -> tactic)
*)
-let tclConstrThen t gl =
- let mind = fst (pf_reduce_to_quantified_ind gl (pf_concl gl))
- in let lconstr =
- (snd (Global.lookup_inductive mind)).mind_consnames
- in let nconstr = Array.length lconstr
- in
+let any_constructor tacopt gl =
+ let t = match tacopt with None -> tclIDTAC | Some t -> t in
+ let mind = fst (pf_reduce_to_quantified_ind gl (pf_concl gl)) in
+ let nconstr =
+ Array.length (snd (Global.lookup_inductive mind)).mind_consnames in
if nconstr = 0 then error "The type has no constructors";
- tclFIRST (List.map (fun i -> (tclTHEN (one_constructor i []) t))
+ tclFIRST (List.map (fun i -> tclTHEN (one_constructor i NoBindings) t)
(interval 1 nconstr)) gl
-let dyn_constructor = function
- | [Integer i; Bindings binds] -> tactic_bind_list (one_constructor i) binds
- | [Integer i; Cbindings binds] -> (one_constructor i) binds
- | [Tac (tac,_)] -> tclConstrThen tac
- | [] -> any_constructor
- | l -> bad_tactic_args "constructor" l
-
-
let left = constructor_tac (Some 2) 1
-let simplest_left = left []
-
-let dyn_left = function
- | [Cbindings binds] -> left binds
- | [Bindings binds] -> tactic_bind_list left binds
- | l -> bad_tactic_args "left" l
+let simplest_left = left NoBindings
let right = constructor_tac (Some 2) 2
-let simplest_right = right []
-
-let dyn_right = function
- | [Cbindings binds] -> right binds
- | [Bindings binds] -> tactic_bind_list right binds
- | l -> bad_tactic_args "right" l
-
+let simplest_right = right NoBindings
let split = constructor_tac (Some 1) 1
-let simplest_split = split []
-
-let dyn_split = function
- | [Cbindings binds] -> split binds
- | [Bindings binds] -> tactic_bind_list split binds
- | l -> bad_tactic_args "split" l
+let simplest_split = split NoBindings
(********************************************)
(* Elimination tactics *)
@@ -1112,17 +901,33 @@ let general_elim (c,lbindc) (elimc,lbindelimc) gl =
(* Elimination tactic with bindings but using the default elimination
* constant associated with the type. *)
-let default_elim (c,lbindc) gl =
+let find_eliminator c gl =
let env = pf_env gl in
let (ind,t) = reduce_to_quantified_ind env (project gl) (pf_type_of gl c) in
let s = elimination_sort_of_goal gl in
- let elimc = Indrec.lookup_eliminator ind s in
- general_elim (c,lbindc) (elimc,[]) gl
-
+ try Indrec.lookup_eliminator ind s
+ with Not_found ->
+ let dir, base = repr_path (path_of_inductive env ind) in
+ let id = Indrec.make_elimination_ident base s in
+ errorlabstrm "default_elim"
+ (str "Cannot find the elimination combinator :" ++
+ pr_id id ++ spc () ++
+ str "The elimination of the inductive definition :" ++
+ pr_id base ++ spc () ++ str "on sort " ++
+ spc () ++ print_sort (new_sort_in_family s) ++
+ str " is probably not allowed")
+
+let default_elim (c,lbindc) gl =
+ general_elim (c,lbindc) (find_eliminator c gl,NoBindings) gl
+
+let elim (c,lbindc) elim gl =
+ match elim with
+ | Some (elimc,lbindelimc) -> general_elim (c,lbindc) (elimc,lbindelimc) gl
+ | None -> general_elim (c,lbindc) (find_eliminator c gl,NoBindings) gl
(* The simplest elimination tactic, with no substitutions at all. *)
-let simplest_elim c = default_elim (c,[])
+let simplest_elim c = default_elim (c,NoBindings)
(* Elimination in hypothesis *)
@@ -1383,11 +1188,6 @@ let find_atomic_param_of_ind mind indtyp =
Others solutions are welcome *)
-(*
-type hyp_status =
-let hyps_map
-*)
-
exception Shunt of identifier option
let cook_sign hyp0 indvars env =
@@ -1438,44 +1238,12 @@ let cook_sign hyp0 indvars env =
let statuslists = (!lstatus,List.rev !rstatus) in
(statuslists, lhyp0, !indhyps, !decldeps)
-
-(* Vieille version en une seule passe grace à l'ordre supérieur mais
- trop difficile à comprendre
-
-let cook_sign hyp0 indvars sign =
- let finaldeps = ref ([],[]) in
- let indhyps = ref [] in
- let hyp0succ = ref None in
- let cook_init (hdeps,tdeps) rhyp before =
- finaldeps := (List.rev hdeps, List.rev tdeps);
- (None, []) in
- let cook_hyp compute_rhyp hyp typ ((hdeps,tdeps) as deps) =
- fun rhyp before ->
- match () with
- _ when (List.mem hyp indvars)
- -> let result = compute_rhyp deps rhyp before in
- indhyps := hyp::!indhyps; result
- | _ when hyp = hyp0
- -> let (lhyp,statl) = compute_rhyp deps rhyp true in
- hyp0succ := lhyp; (None (* fake value *),statl)
- | _ when (List.exists (fun id -> occur_var id typ) (hyp0::indvars)
- or List.exists (fun id -> occur_var id typ) hdeps)
- -> let deps' = (hyp::hdeps, typ::tdeps) in
- let (lhyp,statl) = compute_rhyp deps' rhyp before in
- let hyp = if before then lhyp else rhyp in
- (lhyp,(DEPENDENT (before,hyp,hyp))::statl)
- | _ ->
- let (_,statl) = compute_rhyp deps (Some hyp) before
- in (Some hyp, statl)
- in let (_,statuslist) = it_sign cook_hyp cook_init sign ([],[]) None false in
- (statuslist, !hyp0succ, !indhyps, !finaldeps)
-*)
-
-let induction_tac varname typ (elimc,elimt) gl =
+let induction_tac varname typ (elimc,elimt,lbindelimc) gl =
let c = mkVar varname in
let (wc,kONT) = startWalk gl in
- let indclause = make_clenv_binding wc (c,typ) [] in
- let elimclause = make_clenv_binding wc (mkCast (elimc,elimt),elimt) [] in
+ let indclause = make_clenv_binding wc (c,typ) NoBindings in
+ let elimclause =
+ make_clenv_binding wc (mkCast (elimc,elimt),elimt) lbindelimc in
elimination_clause_scheme kONT elimclause indclause gl
let is_indhyp p n t =
@@ -1510,9 +1278,9 @@ let compute_elim_signature_and_roughly_check elimt mind =
| Prod (_,t,c) -> (check_branch n t lra.(n)) :: (check_elim c (n+1))
| _ -> error "Not an eliminator: some constructor case is lacking" in
let _,elimt3 = decompose_prod_n npred elimt2 in
- check_elim elimt3 0
+ Array.of_list (check_elim elimt3 0)
-let induction_from_context isrec style hyp0 gl =
+let induction_from_context isrec style elim hyp0 gl =
(*test suivant sans doute inutile car refait par le letin_tac*)
if List.mem hyp0 (ids_of_named_context (Global.named_context())) then
errorlabstrm "induction"
@@ -1520,12 +1288,17 @@ let induction_from_context isrec style hyp0 gl =
let tmptyp0 = pf_get_hyp_typ gl hyp0 in
let env = pf_env gl in
let (mind,typ0) = pf_reduce_to_quantified_ind gl tmptyp0 in
- let indvars = find_atomic_param_of_ind mind (snd (decompose_prod typ0)) in
- let elimc =
- if isrec then Indrec.lookup_eliminator mind (elimination_sort_of_goal gl)
- else Indrec.make_case_gen env (project gl) mind (elimination_sort_of_goal gl)
- in
+ let elimc,lbindelimc = match elim with
+ | None ->
+ let s = elimination_sort_of_goal gl in
+ (if isrec then Indrec.lookup_eliminator mind s
+ else Indrec.make_case_gen env (project gl) mind s),
+ NoBindings
+ | Some elim ->
+ (* Not really robust: no control on the form of the combinator *)
+ elim in
let elimt = pf_type_of gl elimc in
+ let indvars = find_atomic_param_of_ind mind (snd (decompose_prod typ0)) in
let (statlists,lhyp0,indhyps,deps) = cook_sign hyp0 indvars env in
let tmpcl = it_mkNamedProd_or_LetIn (pf_concl gl) deps in
let lr = compute_elim_signature_and_roughly_check elimt mind in
@@ -1538,32 +1311,35 @@ let induction_from_context isrec style hyp0 gl =
eux qui ouvrent de nouveaux buts arrivent en premier dans la
liste des sous-buts du fait qu'ils sont le plus à gauche dans le
combinateur engendré par make_case_gen (un "Cases (hyp0 ?) of
- ...") et on ne peut plus appliquer tclTHENST après; en revanche,
+ ...") et on ne peut plus appliquer tclTHENSI après; en revanche,
comme lookup_eliminator renvoie un combinateur de la forme
"ind_rec ... (hyp0 ?)", les buts correspondant à des arguments de
- hyp0 sont maintenant à la fin et tclTHENS marche !!! *)
+ hyp0 sont maintenant à la fin et tclTHENSI marche !!! *)
+(*
if not isrec && nb_prod typ0 <> 0 && lr <> [] (* passe-droit *) then
error "Cases analysis on a functional term not implemented";
-
+*)
tclTHENLIST
[ apply_type tmpcl args;
thin dephyps;
- tclTHENST
+ (if isrec then tclTHENFIRSTn else tclTHENLASTn)
(tclTHEN
- (induction_tac hyp0 typ0 (elimc,elimt))
+ (induction_tac hyp0 typ0 (elimc,elimt,lbindelimc))
(thin (hyp0::indhyps)))
- (List.map
+ (Array.map
(induct_discharge style mind statlists hyp0 lhyp0
(List.rev dephyps)) lr)
- tclIDTAC ]
+ ]
gl
let induction_with_atomization_of_ind_arg isrec hyp0 =
tclTHEN
(atomize_param_of_ind hyp0)
- (induction_from_context isrec false hyp0)
+ (induction_from_context isrec false None hyp0)
-let new_induct isrec c gl =
+(* This is Induction since V7 ("natural" induction both in quantified
+ premisses and introduced ones) *)
+let new_induct_gen isrec c gl =
match kind_of_term c with
| Var id when not (mem_named_context id (Global.named_context())) ->
induction_with_atomization_of_ind_arg isrec id gl
@@ -1575,60 +1351,34 @@ let new_induct isrec c gl =
(letin_tac true (Name id) c (None,[]))
(induction_with_atomization_of_ind_arg isrec id) gl
-(*
-let new_induct_nodep isrec n =
- tclTHEN (intros_until_n n) (induction_with_atomization_of_ind_arg isrec None)
-*)
+let new_induct_destruct isrec = function
+ | ElimOnConstr c -> new_induct_gen isrec c
+ | ElimOnAnonHyp n ->
+ tclTHEN (intros_until_n n) (tclLAST_HYP (new_induct_gen isrec))
+ (* Identifier apart because id can be quantified in goal and not typable *)
+ | ElimOnIdent (_,id) ->
+ tclTHEN (tclTRY (intros_until_id id)) (new_induct_gen isrec (mkVar id))
+
+let new_induct = new_induct_destruct true
+let new_destruct = new_induct_destruct false
(* The registered tactic, which calls the default elimination
* if no elimination constant is provided. *)
-
-let dyn_elim = function
- | [Constr mp; Cbindings mpbinds] ->
- default_elim (mp,mpbinds)
- | [Command mp; Bindings mpbinds] ->
- tactic_com_bind_list default_elim (mp,mpbinds)
- | [Command mp; Bindings mpbinds; Command elimc; Bindings elimcbinds] ->
- let funpair2funlist f = (function [x;y] -> f x y | _ -> assert false) in
- tactic_com_bind_list_list
- (funpair2funlist general_elim)
- [(mp,mpbinds);(elimc,elimcbinds)]
- | [Constr mp; Cbindings mpbinds; Constr elimc; Cbindings elimcbinds] ->
- general_elim (mp,mpbinds) (elimc,elimcbinds)
- | l -> bad_tactic_args "elim" l
(* Induction tactics *)
(* This was Induction before 6.3 (induction only in quantified premisses) *)
-let raw_induct s = tclTHEN (intros_until s) (tclLAST_HYP simplest_elim)
+let raw_induct s = tclTHEN (intros_until_id s) (tclLAST_HYP simplest_elim)
let raw_induct_nodep n = tclTHEN (intros_until_n n) (tclLAST_HYP simplest_elim)
(* This was Induction in 6.3 (hybrid form) *)
-let old_induct s =tclORELSE (raw_induct s) (induction_from_context true true s)
+let old_induct_id s =
+ tclORELSE (raw_induct s) (induction_from_context true true None s)
let old_induct_nodep = raw_induct_nodep
-(* This is Induction since V7 ("natural" induction both in quantified
- premisses and introduced ones) *)
-let dyn_new_induct = function
- | [(Command c)] -> tactic_com (new_induct true) c
- | [(Constr x)] -> new_induct true x
- (* Identifier apart because id can be quantified in goal and not typable *)
- | [Integer _ | Identifier _ as arg] ->
- tactic_try_intros_until (fun id -> new_induct true (mkVar id)) arg
- | l -> bad_tactic_args "induct" l
-
-(* This was Induction before 6.3 (induction only in quantified premisses)
-let dyn_raw_induct = function
- | [Identifier x] -> raw_induct x
- | [Integer n] -> raw_induct_nodep n
- | l -> bad_tactic_args "raw_induct" l
-*)
-
-(* This was Induction in 6.3 (hybrid form) *)
-let dyn_old_induct = function
- | [(Identifier n)] -> old_induct n
- | [Integer n] -> raw_induct_nodep n
- | l -> bad_tactic_args "raw_induct" l
+let old_induct = function
+ | NamedHyp id -> old_induct_id id
+ | AnonHyp n -> old_induct_nodep n
(* Case analysis tactics *)
@@ -1640,37 +1390,20 @@ let general_case_analysis (c,lbindc) gl =
let case = if occur_term c (pf_concl gl) then Indrec.make_case_dep
else Indrec.make_case_gen in
let elim = case env sigma mind sort in
- general_elim (c,lbindc) (elim,[]) gl
+ general_elim (c,lbindc) (elim,NoBindings) gl
-let simplest_case c = general_case_analysis (c,[])
-
-let dyn_case =function
- | [Constr mp; Cbindings mpbinds] ->
- general_case_analysis (mp,mpbinds)
- | [Command mp; Bindings mpbinds] ->
- tactic_com_bind_list general_case_analysis (mp,mpbinds)
- | l -> bad_tactic_args "case" l
-
+let simplest_case c = general_case_analysis (c,NoBindings)
(* Destruction tactics *)
-let destruct s = (tclTHEN (intros_until s) (tclLAST_HYP simplest_case))
-let destruct_nodep n = (tclTHEN (intros_until_n n) (tclLAST_HYP simplest_case))
+let old_destruct_id s =
+ (tclTHEN (intros_until_id s) (tclLAST_HYP simplest_case))
+let old_destruct_nodep n =
+ (tclTHEN (intros_until_n n) (tclLAST_HYP simplest_case))
-let dyn_new_destruct = function
- | [(Command c)] -> tactic_com (new_induct false) c
- | [(Constr x)] -> new_induct false x
- (* Identifier apart because id can be quantified in goal and not typable *)
- | [Integer _ | Identifier _ as arg] ->
- tactic_try_intros_until (fun id -> new_induct false (mkVar id)) arg
- | l -> bad_tactic_args "induct" l
-
-let dyn_old_destruct = function
- | [Identifier x] -> destruct x
- | [Integer n] -> destruct_nodep n
- | l -> bad_tactic_args "destruct" l
-
-let dyn_destruct = dyn_old_destruct
+let old_destruct = function
+ | NamedHyp id -> old_destruct_id id
+ | AnonHyp n -> old_destruct_nodep n
(*
* Eliminations giving the type instead of the proof.
@@ -1695,22 +1428,12 @@ let elim_type t gl =
let elimc = Indrec.lookup_eliminator ind (elimination_sort_of_goal gl) in
elim_scheme_type elimc t gl
-let dyn_elim_type = function
- | [Constr c] -> elim_type c
- | [Command com] -> tactic_com_sort elim_type com
- | l -> bad_tactic_args "elim_type" l
-
let case_type t gl =
let (ind,t) = pf_reduce_to_atomic_ind gl t in
let env = pf_env gl in
let elimc = Indrec.make_case_gen env (project gl) ind (elimination_sort_of_goal gl) in
elim_scheme_type elimc t gl
-let dyn_case_type = function
- | [Constr c] -> case_type c
- | [Command com] -> tactic_com case_type com
- | l -> bad_tactic_args "case_type" l
-
(* Some eliminations frequently used *)
@@ -1750,14 +1473,15 @@ let orE id gl =
let dorE b cls gl =
match cls with
| (Some id) -> orE id gl
- | None -> (if b then right else left) [] gl
+ | None -> (if b then right else left) NoBindings gl
let impE id gl =
let t = pf_get_hyp_typ gl id in
if is_imp_term (pf_hnf_constr gl t) then
let (dom, _, rng) = destProd (pf_hnf_constr gl t) in
- (tclTHENS (cut_intro rng)
- [tclIDTAC;apply_term (mkVar id) [mkMeta (new_meta())]]) gl
+ tclTHENLAST
+ (cut_intro rng)
+ (apply_term (mkVar id) [mkMeta (new_meta())]) gl
else
errorlabstrm "impE"
(str("Tactic impE expects "^(string_of_id id)^
@@ -1772,55 +1496,15 @@ let dImp cls gl =
(* Tactics related with logic connectives *)
(************************************************)
-(* Contradiction *)
-
-let contradiction_on_hyp id gl =
- let hyp = pf_get_hyp_typ gl id in
- if is_empty_type hyp then
- simplest_elim (mkVar id) gl
- else
- error "Not a contradiction"
-
-(* Absurd *)
-let absurd c gls =
- (tclTHENS
- (tclTHEN (elim_type (build_coq_False ())) (cut c))
- ([(tclTHENS
- (cut (applist(build_coq_not (),[c])))
- ([(tclTHEN intros
- ((fun gl ->
- let ida = pf_nth_hyp_id gl 1
- and idna = pf_nth_hyp_id gl 2 in
- exact_no_check (applist(mkVar idna,[mkVar ida])) gl)));
- tclIDTAC]));
- tclIDTAC])) gls
-
-let dyn_absurd = function
- | [Constr c] -> absurd c
- | [Command com] -> tactic_com_sort absurd com
- | l -> bad_tactic_args "absurd" l
-
-let contradiction gls =
- tclTHENLIST [ intros; elim_type (build_coq_False ()); assumption ] gls
-
-let dyn_contradiction = function
- | [] -> contradiction
- | l -> bad_tactic_args "contradiction" l
-
-(* Relfexivity tactics *)
+(* Reflexivity tactics *)
let reflexivity gl =
match match_with_equation (pf_concl gl) with
| None -> error "The conclusion is not a substitutive equation"
- | Some (hdcncl,args) -> one_constructor 1 [] gl
+ | Some (hdcncl,args) -> one_constructor 1 NoBindings gl
let intros_reflexivity = (tclTHEN intros reflexivity)
-let dyn_reflexivity = function
- | [] -> intros_reflexivity
- | _ -> errorlabstrm "Tactics.reflexivity"
- (str "Tactic applied to bad arguments!")
-
(* Symmetry tactics *)
(* This tactic first tries to apply a constant named sym_eq, where eq
@@ -1842,19 +1526,16 @@ let symmetry gl =
| [c1;c2] -> mkApp (hdcncl, [| c2; c1 |])
| _ -> assert false
in
- (tclTHENS (cut symc)
- [ tclTHENLIST [ intro;
- tclLAST_HYP simplest_case;
- one_constructor 1 [] ];
- tclIDTAC ]) gl
+ tclTHENLAST (cut symc)
+ (tclTHENLIST
+ [ intro;
+ tclLAST_HYP simplest_case;
+ one_constructor 1 NoBindings ])
+ gl
end
let intros_symmetry = (tclTHEN intros symmetry)
-let dyn_symmetry = function
- | [] -> intros_symmetry
- | l -> bad_tactic_args "symmetry" l
-
(* Transitivity tactics *)
(* This tactic first tries to apply a constant named trans_eq, where eq
@@ -1886,22 +1567,16 @@ let transitivity t gl =
| [c1;c2] -> mkApp (hdcncl, [| t; c2 |])
| _ -> assert false
in
- (tclTHENS (cut eq2)
- [tclTHENS (cut eq1)
- [ tclTHENLIST [ tclDO 2 intro;
- tclLAST_HYP simplest_case;
- assumption ];
- tclIDTAC];
- tclIDTAC])gl
+ tclTHENFIRST (cut eq2)
+ (tclTHENFIRST (cut eq1)
+ (tclTHENLIST
+ [ tclDO 2 intro;
+ tclLAST_HYP simplest_case;
+ assumption ])) gl
end
let intros_transitivity n = tclTHEN intros (transitivity n)
-let dyn_transitivity = function
- | [Constr n] -> intros_transitivity n
- | [Command n] -> tactic_com intros_transitivity n
- | l -> bad_tactic_args "transitivity" l
-
(* tactical to save as name a subproof such that the generalisation of
the current goal, abstracted with respect to the local signature,
is solved by tac *)
@@ -1922,8 +1597,8 @@ let abstract_subproof name tac gls =
in
if occur_existential concl then error "Abstract cannot handle existentials";
let lemme =
- start_proof na NeverDischarge current_sign concl;
- let _,(const,strength) =
+ start_proof na (false,Nametab.NeverDischarge) current_sign concl (fun _ _ -> ());
+ let _,(const,(_,strength),_) =
try
by (tclCOMPLETE (tclTHEN (tclDO (List.length sign) intro) tac));
let r = cook_proof () in
@@ -1947,15 +1622,3 @@ let tclABSTRACT name_op tac gls =
| None -> add_suffix (get_current_proof_name ()) "_subproof"
in
abstract_subproof s tac gls
-
-let dyn_tclABSTRACT =
- hide_tactic "ABSTRACT"
- (function
- | [Tac (tac,_)] ->
- tclABSTRACT None tac
- | [Identifier s; Tac (tac,_)] ->
- tclABSTRACT (Some s) tac
- | _ -> invalid_arg "tclABSTRACT")
-
-
-