aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar msozeau <msozeau@85f007b7-540e-0410-9357-904b9bb8a0f7>2008-09-15 22:21:22 +0000
committerGravatar msozeau <msozeau@85f007b7-540e-0410-9357-904b9bb8a0f7>2008-09-15 22:21:22 +0000
commite1a1ccd3ee9cfd72b6e9105051e5da1bf398451f (patch)
treead475ec7af84ae24a7f78a845f98369a63f5540f
parentc408060c9363eac5ff51f9a1fe8b510b1628c9f9 (diff)
Report improvements in Equations to the dependent elimination tactic:
- Do not touch at the user equalities and so on by using a blocking constant. This avoids the wild autoinjections and subst tactics that were used before. Thanks to Brian Aydemir for an example were this hurt a lot. - Debug the tactic used to simplify induction hypotheses. git-svn-id: svn+ssh://scm.gforge.inria.fr/svn/coq/trunk@11415 85f007b7-540e-0410-9357-904b9bb8a0f7
-rw-r--r--contrib/subtac/equations.ml447
-rw-r--r--test-suite/success/dependentind.v36
-rw-r--r--theories/Program/Equality.v174
3 files changed, 108 insertions, 149 deletions
diff --git a/contrib/subtac/equations.ml4 b/contrib/subtac/equations.ml4
index 515a78280..135fcf11d 100644
--- a/contrib/subtac/equations.ml4
+++ b/contrib/subtac/equations.ml4
@@ -749,7 +749,15 @@ open Evarutil
let lift_substitution n s = map (fun (k, x) -> (k + n, x)) s
let map_substitution s t = map (subst_rel_subst 0 s) t
-let term_of_tree status isevar env (i, delta, ty) tree =
+let term_of_tree status isevar env (i, delta, ty) ann tree =
+(* let envrec = match ann with *)
+(* | None -> [] *)
+(* | Some (loc, i) -> *)
+(* let (n, t) = lookup_rel_id i delta in *)
+(* let t' = lift n t in *)
+
+
+(* in *)
let rec aux = function
| Compute ((ctx, _, pats as lhs), Program rhs) ->
let ty' = substl (rev (constrs_of_lhs ~inacc:false env lhs)) ty in
@@ -903,7 +911,7 @@ let equations_tac = lazy
(TacArg(TacCall(dummy_loc,
ArgArg(dummy_loc, tactics_tac "equations"), []))))
-let define_by_eqs with_comp i l t nt eqs =
+let define_by_eqs with_comp i (l,ann) t nt eqs =
let env = Global.env () in
let isevar = ref (create_evar_defs Evd.empty) in
let (env', sign), impls = interp_context_evars isevar env l in
@@ -951,7 +959,7 @@ let define_by_eqs with_comp i l t nt eqs =
let split = make_split env' prob equations in
(* if valid_tree prob split then *)
let status = (* if is_recursive then Expand else *) Define false in
- let t, ty = term_of_tree status isevar env' prob split in
+ let t, ty = term_of_tree status isevar env' prob ann split in
let undef = undefined_evars !isevar in
let t, ty = if is_recursive then
(it_mkLambda_or_LetIn t fixdecls, it_mkProd_or_LetIn ty fixdecls)
@@ -978,7 +986,7 @@ struct
let deppat_equations : equation list Gram.Entry.e = gec "deppat_equations"
- let binders_let2 : local_binder list Gram.Entry.e = gec "binders_let2"
+ let binders_let2 : (local_binder list * (identifier located option * recursion_order_expr)) Gram.Entry.e = gec "binders_let2"
(* let where_decl : decl_notation Gram.Entry.e = gec "where_decl" *)
@@ -1000,7 +1008,7 @@ GEXTEND Gram
;
binders_let2:
- [ [ l = binders_let -> l ] ]
+ [ [ l = binders_let_fixannot -> l ] ]
;
equation:
@@ -1022,7 +1030,7 @@ let (wit_deppat_equations : Genarg.tlevel deppat_equations_argtype),
(rawwit_deppat_equations : Genarg.rlevel deppat_equations_argtype) =
Genarg.create_arg "deppat_equations"
-type 'a binders_let2_argtype = (local_binder list, 'a) Genarg.abstract_argument_type
+type 'a binders_let2_argtype = (local_binder list * (identifier located option * recursion_order_expr), 'a) Genarg.abstract_argument_type
let (wit_binders_let2 : Genarg.tlevel binders_let2_argtype),
(globwit_binders_let2 : Genarg.glevel binders_let2_argtype),
@@ -1096,7 +1104,7 @@ let coq_eq_refl = lazy ((Coqlib.build_coq_eq_data ()).Coqlib.refl)
let coq_heq = lazy (Coqlib.coq_constant "mkHEq" ["Logic";"JMeq"] "JMeq")
let coq_heq_refl = lazy (Coqlib.coq_constant "mkHEq" ["Logic";"JMeq"] "JMeq_refl")
-let simplify_hyp id gl =
+let specialize_hyp id gl =
let env = pf_env gl in
let ty = pf_get_hyp_typ gl id in
let evars = ref (create_evar_defs (project gl)) in
@@ -1117,18 +1125,25 @@ let simplify_hyp id gl =
aux true (mkApp (acc, [| p |])) (subst1 p b)
else error "Unconvertible members of an heterogeneous equality"
| _ ->
- if in_eqs then acc, ty
+ if in_eqs then acc, in_eqs, ty
else
let e = e_new_evar evars env t in
aux false (mkApp (acc, [| e |])) (subst1 e b))
- | t -> acc, ty
+ | t -> acc, in_eqs, ty
in
- let acc, ty = aux false (mkVar id) ty in
- let ty = Evarutil.nf_isevar !evars ty in
- tclTHENFIRST
- (fun g -> Tacmach.internal_cut true id ty g)
- (exact_no_check (Evarutil.nf_isevar !evars acc)) gl
+ try
+ let acc, worked, ty = aux false (mkVar id) ty in
+ let ty = Evarutil.nf_isevar !evars ty in
+ if worked then
+ tclTHENFIRST
+ (fun g -> Tacmach.internal_cut true id ty g)
+ (exact_no_check (Evarutil.nf_isevar !evars acc)) gl
+ else tclFAIL 0 (str "Nothing to do in hypothesis " ++ pr_id id) gl
+ with e -> tclFAIL 0 (Cerrors.explain_exn e) gl
-TACTIC EXTEND simplify_hyp
-[ "simplify_hyp" ident(id) ] -> [ simplify_hyp id ]
+TACTIC EXTEND specialize_hyp
+[ "specialize_hypothesis" constr(c) ] -> [
+ match kind_of_term c with
+ | Var id -> specialize_hyp id
+ | _ -> tclFAIL 0 (str "Not an hypothesis") ]
END
diff --git a/test-suite/success/dependentind.v b/test-suite/success/dependentind.v
index 48b07db83..3f315ccb7 100644
--- a/test-suite/success/dependentind.v
+++ b/test-suite/success/dependentind.v
@@ -40,7 +40,7 @@ Delimit Scope context_scope with ctx.
Arguments Scope snoc [context_scope].
-Notation " Γ , τ " := (snoc Γ τ) (at level 25, t at next level, left associativity) : context_scope.
+Notation " Γ ,, τ " := (snoc Γ τ) (at level 25, t at next level, left associativity).
Fixpoint conc (Δ Γ : ctx) : ctx :=
match Δ with
@@ -52,42 +52,36 @@ Notation " Γ ;; Δ " := (conc Δ Γ) (at level 25, left associativity) : contex
Inductive term : ctx -> type -> Type :=
| ax : forall Γ τ, term (snoc Γ τ) τ
-| weak : forall Γ τ, term Γ τ -> forall τ', term (snoc Γ τ') τ
+| weak : forall Γ τ, term Γ τ -> forall τ', term (Γ ,, τ') τ
| abs : forall Γ τ τ', term (snoc Γ τ) τ' -> term Γ (τ --> τ')
| app : forall Γ τ τ', term Γ (τ --> τ') -> term Γ τ -> term Γ τ'.
-Notation " Γ |- τ " := (term Γ τ) (at level 0).
+Hint Constructors term : lambda.
+Notation " Γ |-- τ " := (term Γ τ) (at level 0) : type_scope.
Lemma weakening : forall Γ Δ τ, term (Γ ;; Δ) τ ->
- forall τ', term (Γ , τ' ;; Δ) τ.
-Proof with simpl in * ; auto ; simpl_depind.
+ forall τ', term (Γ ,, τ' ;; Δ) τ.
+Proof with simpl in * ; simplify_dep_elim ; simplify_IH_hyps ; eauto with lambda.
intros Γ Δ τ H.
dependent induction H.
destruct Δ...
- apply weak ; apply ax.
-
- apply ax.
-
- destruct Δ...
- specialize (IHterm empty Γ)...
- apply weak...
-
- apply weak...
destruct Δ...
- apply weak. apply abs ; apply H.
+ destruct Δ...
apply abs...
- specialize (IHterm (Δ, t, τ)%ctx Γ0)...
+
+ specialize (IHterm (Δ,, t,, τ)%ctx Γ0)...
+ intro.
apply app with τ...
Qed.
-Lemma exchange : forall Γ Δ α β τ, term (Γ, α, β ;; Δ) τ -> term (Γ, β, α ;; Δ) τ.
-Proof with simpl in * ; simpl_depind ; auto.
+Lemma exchange : forall Γ Δ α β τ, term (Γ,, α,, β ;; Δ) τ -> term (Γ,, β,, α ;; Δ) τ.
+Proof with simpl in * ; simplify_dep_elim ; simplify_IH_hyps ; auto.
intros until 1.
dependent induction H.
@@ -97,12 +91,12 @@ Proof with simpl in * ; simpl_depind ; auto.
apply ax.
destruct Δ...
- pose (weakening Γ0 (empty, α))...
+ pose (weakening Γ0 (empty,, α))...
apply weak...
- apply abs...
- specialize (IHterm (Δ, τ)%ctx Γ0 α β)...
+ apply abs...
+ specialize (IHterm (Δ ,, τ))...
eapply app with τ...
Save.
diff --git a/theories/Program/Equality.v b/theories/Program/Equality.v
index c83b5d38d..2b914ace7 100644
--- a/theories/Program/Equality.v
+++ b/theories/Program/Equality.v
@@ -259,56 +259,6 @@ Ltac simpl_depind_l := subst_left_no_fail ; autoinjections_left ; try discrimina
Ltac simpl_depind_r := subst_right_no_fail ; autoinjections_right ; try discriminates ;
simpl_JMeq ; simpl_existTs ; simpl_IHs_eqs.
-(** The following tactics allow to do induction on an already instantiated inductive predicate
- by first generalizing it and adding the proper equalities to the context, in a maner similar to
- the BasicElim tactic of "Elimination with a motive" by Conor McBride. *)
-
-(** The [do_depind] higher-order tactic takes an induction tactic as argument and an hypothesis
- and starts a dependent induction using this tactic. *)
-
-Ltac do_depind tac H :=
- generalize_eqs_vars H ; tac H ; repeat progress simpl_depind_r ; subst_left_no_fail.
-
-(** A variant where generalized variables should be given by the user. *)
-
-Ltac do_depind' tac H :=
- generalize_eqs H ; tac H ; repeat progress simpl_depind_l ; subst_right_no_fail.
-
-(** Calls [destruct] on the generalized hypothesis, results should be similar to inversion.
- By default, we don't try to generalize the hyp by its variable indices. *)
-
-Tactic Notation "dependent" "destruction" ident(H) :=
- do_depind' ltac:(fun hyp => destruct hyp ; intros) H.
-
-Tactic Notation "dependent" "destruction" ident(H) "using" constr(c) :=
- do_depind' ltac:(fun hyp => destruct hyp using c ; intros) H.
-
-(** This tactic also generalizes the goal by the given variables before the induction. *)
-
-Tactic Notation "dependent" "destruction" ident(H) "generalizing" ne_hyp_list(l) :=
- do_depind' ltac:(fun hyp => revert l ; destruct hyp ; intros) H.
-
-Tactic Notation "dependent" "destruction" ident(H) "generalizing" ne_hyp_list(l) "using" constr(c) :=
- do_depind' ltac:(fun hyp => revert l ; destruct hyp using c ; intros) H.
-
-(** Then we have wrappers for usual calls to induction. One can customize the induction tactic by
- writting another wrapper calling do_depind. We suppose the hyp has to be generalized before
- calling [induction]. *)
-
-Tactic Notation "dependent" "induction" ident(H) :=
- do_depind ltac:(fun hyp => induction hyp ; intros) H.
-
-Tactic Notation "dependent" "induction" ident(H) "using" constr(c) :=
- do_depind ltac:(fun hyp => induction hyp using c ; intros) H.
-
-(** This tactic also generalizes the goal by the given variables before the induction. *)
-
-Tactic Notation "dependent" "induction" ident(H) "generalizing" ne_hyp_list(l) :=
- do_depind' ltac:(fun hyp => generalize l ; clear l ; induction hyp ; intros) H.
-
-Tactic Notation "dependent" "induction" ident(H) "generalizing" ne_hyp_list(l) "using" constr(c) :=
- do_depind' ltac:(fun hyp => generalize l ; clear l ; induction hyp using c ; intros) H.
-
(** Support for the [Equations] command.
These tactics implement the necessary machinery to solve goals produced by the
[Equations] command relative to dependent pattern-matching.
@@ -349,6 +299,18 @@ Ltac elim_tac tac p :=
Ltac elim_case p := elim_tac ltac:(fun p el => destruct p using el) p.
Ltac elim_ind p := elim_tac ltac:(fun p el => induction p using el) p.
+(** The [BelowPackage] class provides the definition of a [Below] predicate for some datatype,
+ allowing to talk about course-of-value recursion on it. *)
+
+Class BelowPackage (A : Type) :=
+ Below : A -> Type ;
+ below : Π (a : A), Below a.
+
+(** The [Recursor] class defines a recursor on a type, based on some definition of [Below]. *)
+
+Class Recursor (A : Type) (BP : BelowPackage A) :=
+ rec_type : A -> Type ; rec : Π (a : A), rec_type a.
+
(** Lemmas used by the simplifier, mainly rephrasings of [eq_rect], [eq_ind]. *)
Lemma solution_left : Π A (B : A -> Type) (t : A), B t -> (Π x, x = t -> B x).
@@ -385,6 +347,11 @@ Ltac unfold_equations := repeat progress autosimpl with equations.
Ltac simplify_equations := repeat (unfold_equations ; simplify_eqs).
+(** We will use the [block_induction] definition to separate the goal from the
+ equalities generated by the tactic. *)
+
+Definition block_dep_elim {A : Type} (a : A) := a.
+
(** Using these we can make a simplifier that will perform the unification
steps needed to put the goal in normalised form (provided there are only
constructor forms). Compare with the lemma 16 of the paper.
@@ -408,7 +375,7 @@ Ltac simplify_one_dep_elim_term c :=
intros hyp ; elimtype False ; discriminate
| ?x = ?y -> _ => let hyp := fresh in
intros hyp ; case hyp ; clear hyp
- | id ?T => fail 1 (* Do not put any part of the rhs in the hyps *)
+ | block_dep_elim ?T => fail 1 (* Do not put any part of the rhs in the hyps *)
| _ => intro
end.
@@ -470,8 +437,8 @@ Ltac simpl_intros m := ((apply m || refine m) ; auto) || (intro ; simpl_intros m
(** Hopefully the first branch suffices. *)
Ltac try_intros m :=
- solve [ intros ; unfold id ; refine m || apply m ] ||
- solve [ unfold id ; simpl_intros m ].
+ solve [ intros ; unfold block_dep_elim ; refine m || apply m ] ||
+ solve [ unfold block_dep_elim ; simpl_intros m ].
(** To solve a goal by inversion on a particular target. *)
@@ -504,11 +471,13 @@ Ltac intro_prototypes :=
| _ => idtac
end.
-Ltac do_case p := destruct p || elim_case p.
+Ltac do_case p := destruct p || elim_case p || (case p ; clear p).
-Ltac idify := match goal with [ |- ?T ] => change (id T) end.
+Ltac dep_elimify := match goal with [ |- ?T ] => change (block_dep_elim T) end.
-Ltac case_last := idify ;
+Ltac un_dep_elimify := unfold block_dep_elim in *.
+
+Ltac case_last := dep_elimify ;
on_last_hyp ltac:(fun p =>
let ty := type of p in
match ty with
@@ -534,76 +503,57 @@ Ltac equations := set_eos ;
| _ => nonrec_equations
end.
-(*
-Equations NoConfusion_nat (P : Prop) (x y : nat) : Prop :=
-NoConfusion_nat P 0 0 := P -> P ;
-NoConfusion_nat P 0 (S y) := P ;
-NoConfusion_nat P (S x) 0 := P ;
-NoConfusion_nat P (S x) (S y) := (x = y -> P) -> P.
-
- Solve Obligations using equations.
-
-Equations noConfusion_nat (P : Prop) (x y : nat) (H : x = y) : NoConfusion_nat P x y :=
-noConfusion_nat P 0 0 refl := λ p, p ;
-noConfusion_nat P (S n) (S n) refl := λ p : n = n -> P, p refl.
-
- Solve Obligations using equations.
-
-Instance nat_noconf : NoConfusionPackage nat :=
- NoConfusion := λ P, Π x y, x = y -> NoConfusion_nat P x y ;
- noConfusion := λ P x y, noConfusion_nat P x y.
+(** The following tactics allow to do induction on an already instantiated inductive predicate
+ by first generalizing it and adding the proper equalities to the context, in a maner similar to
+ the BasicElim tactic of "Elimination with a motive" by Conor McBride. *)
-Equations NoConfusion_bool (P : Prop) (x y : bool) : Prop :=
-NoConfusion_bool P true true := P -> P ;
-NoConfusion_bool P false false := P -> P ;
-NoConfusion_bool P true false := P ;
-NoConfusion_bool P false true := P.
+(** The [do_depind] higher-order tactic takes an induction tactic as argument and an hypothesis
+ and starts a dependent induction using this tactic. *)
- Solve Obligations using equations.
+Ltac do_depind tac H :=
+ (try intros until H) ; dep_elimify ; generalize_eqs_vars H ; tac H ; simplify_dep_elim ; un_dep_elimify.
-Equations noConfusion_bool (P : Prop) (x y : bool) (H : x = y) : NoConfusion_bool P x y :=
-noConfusion_bool P true true refl := λ p, p ;
-noConfusion_bool P false false refl := λ p, p.
+(** A variant where generalized variables should be given by the user. *)
- Solve Obligations using equations.
+Ltac do_depind' tac H :=
+ (try intros until H) ; dep_elimify ; generalize_eqs H ; tac H ; simplify_dep_elim ; un_dep_elimify.
-Instance bool_noconf : NoConfusionPackage bool :=
- NoConfusion := λ P, Π x y, x = y -> NoConfusion_bool P x y ;
- noConfusion := λ P x y, noConfusion_bool P x y.
+(** Calls [destruct] on the generalized hypothesis, results should be similar to inversion.
+ By default, we don't try to generalize the hyp by its variable indices. *)
-Equations NoConfusion_unit (P : Prop) (x y : unit) : Prop :=
-NoConfusion_unit P tt tt := P -> P.
+Tactic Notation "dependent" "destruction" ident(H) :=
+ do_depind' ltac:(fun hyp => destruct hyp) H.
- Solve Obligations using equations.
+Tactic Notation "dependent" "destruction" ident(H) "using" constr(c) :=
+ do_depind' ltac:(fun hyp => destruct hyp using c) H.
-Equations noConfusion_unit (P : Prop) (x y : unit) (H : x = y) : NoConfusion_unit P x y :=
-noConfusion_unit P tt tt refl := λ p, p.
+(** This tactic also generalizes the goal by the given variables before the induction. *)
- Solve Obligations using equations.
+Tactic Notation "dependent" "destruction" ident(H) "generalizing" ne_hyp_list(l) :=
+ do_depind' ltac:(fun hyp => revert l ; destruct hyp) H.
-Instance unit_noconf : NoConfusionPackage unit :=
- NoConfusion := λ P, Π x y, x = y -> NoConfusion_unit P x y ;
- noConfusion := λ P x y, noConfusion_unit P x y.
+Tactic Notation "dependent" "destruction" ident(H) "generalizing" ne_hyp_list(l) "using" constr(c) :=
+ do_depind' ltac:(fun hyp => revert l ; destruct hyp using c) H.
-Require Import List.
+(** Then we have wrappers for usual calls to induction. One can customize the induction tactic by
+ writting another wrapper calling do_depind. We suppose the hyp has to be generalized before
+ calling [induction]. *)
-Implicit Arguments nil [[A]].
+Tactic Notation "dependent" "induction" ident(H) :=
+ do_depind ltac:(fun hyp => induction hyp) H.
-Equations NoConfusion_list (P : Prop) (A : Type) (x y : list A) : Prop :=
-NoConfusion_list P A nil nil := P -> P ;
-NoConfusion_list P A nil (cons a y) := P ;
-NoConfusion_list P A (cons a x) nil := P ;
-NoConfusion_list P A (cons a x) (cons b y) := (a = b -> x = y -> P) -> P.
+Tactic Notation "dependent" "induction" ident(H) "using" constr(c) :=
+ do_depind ltac:(fun hyp => induction hyp using c) H.
- Solve Obligations using equations.
+(** This tactic also generalizes the goal by the given variables before the induction. *)
-Equations noConfusion_list (P : Prop) A (x y : list A) (H : x = y) : NoConfusion_list P A x y :=
-noConfusion_list P A nil nil refl := λ p, p ;
-noConfusion_list P A (cons a x) (cons a x) refl := λ p : a = a -> x = x -> P, p refl refl.
+Tactic Notation "dependent" "induction" ident(H) "generalizing" ne_hyp_list(l) :=
+ do_depind' ltac:(fun hyp => generalize l ; clear l ; induction hyp) H.
- Solve Obligations using equations.
+Tactic Notation "dependent" "induction" ident(H) "generalizing" ne_hyp_list(l) "using" constr(c) :=
+ do_depind' ltac:(fun hyp => generalize l ; clear l ; induction hyp using c) H.
-Instance list_noconf A : NoConfusionPackage (list A) :=
- NoConfusion := λ P, Π x y, x = y -> NoConfusion_list P A x y ;
- noConfusion := λ P x y, noConfusion_list P A x y.
-*) \ No newline at end of file
+Ltac simplify_IH_hyps := repeat
+ match goal with
+ | [ hyp : _ |- _ ] => specialize_hypothesis hyp
+ end. \ No newline at end of file