Section equatesLemma.
Variables (A0 A1 : Type).
Variables (A2 : forall (x1 : A1), Type).
Variables (A3 : forall (x1 : A1) (x2 : A2 x1), Type).
Variables (A4 : forall (x1 : A1) (x2 : A2 x1) (x3 : A3 x2), Type).
Variables (A5 : forall (x1 : A1) (x2 : A2 x1) (x3 : A3 x2) (x4 : A4 x3), Type).
Variables (A6 : forall (x1 : A1) (x2 : A2 x1) (x3 : A3 x2) (x4 : A4 x3) (x5 : A5 x4), Type).
Proof using. intros. subst. auto. Qed.
Proof using. intros. subst. auto. Qed.
Proof using. intros. subst. auto. Qed.
Proof using. intros. subst. auto. Qed.
Proof using. intros. subst. auto. Qed.
Proof using. intros. subst. auto. Qed.
Proof using. intros. subst. auto. Qed.
End equatesLemma.
Ltac equates_lemma n :=
match number_to_nat n with
| 0 => constr:(equates_0)
| 1 => constr:(equates_1)
| 2 => constr:(equates_2)
| 3 => constr:(equates_3)
| 4 => constr:(equates_4)
| 5 => constr:(equates_5)
| 6 => constr:(equates_6)
| _ => fail 100 "equates tactic only support up to arity 6"
end.
Ltac equates_one n :=
let L := equates_lemma n in
eapply L.
Ltac equates_several E cont :=
let all_pos := match type of E with
| List.list Boxer => constr:(E)
| _ => constr:((boxer E)::nil)
end in
let rec go pos :=
match pos with
| nil => cont tt
| (boxer ?n)::?pos' => equates_one n; [ go pos' | ]
end in
go all_pos.
Tactic Notation "equates" constr(E) :=
equates_several E ltac:(fun _ => idtac).
Tactic Notation "equates" constr(n1) constr(n2) :=
equates (>> n1 n2).
Tactic Notation "equates" constr(n1) constr(n2) constr(n3) :=
equates (>> n1 n2 n3).
Tactic Notation "equates" constr(n1) constr(n2) constr(n3) constr(n4) :=
equates (>> n1 n2 n3 n4).
(** [applys_eq H i1 .. iK] is the same as [equates i1 .. iK] followed by [applys H] on the first subgoal.  DEPRECATED: use [applys_eq H] instead. *)
Tactic Notation "applys_eq" constr(H) constr(E) :=
equates_several E ltac:(fun _ => sapply H).
Tactic Notation "applys_eq" constr(H) constr(n1) constr(n2) :=
applys_eq H (>> n1 n2).
Tactic Notation "applys_eq" constr(H) constr(n1) constr(n2) constr(n3) :=
applys_eq H (>> n1 n2 n3).
Tactic Notation "applys_eq" constr(H) constr(n1) constr(n2) constr(n3) constr(n4) :=
applys_eq H (>> n1 n2 n3 n4).
(** [applys_eq H] helps proving a goal of the form [P x1 .. xN] from an hypothesis [H] that concludes [P y1 .. yN], where the arguments [xi] and [yi] may or may not be convertible. Equalities are produced for all arguments that don't unify.  The tactic invokes [equates] on all arguments, then calls [applys K], and attempts [reflexivity] on the side equalities. *)

Lemma applys_eq_init : forall (P Q:Prop),
P = Q ->
Q ->
P.