Interaction between type classes and auto tactic

Question

Consider this simple development. I have two trivial data types:

Inductive A :=
| A1
| A2.

Inductive B :=
| B1 : A -> B
| B2.

Now I introduce a concept of relation and define ordering on data types A and B expressed as an inductive data type:

Definition relation (X : Type) := X -> X -> Prop.

Reserved Notation "a1 '<=A' a2" (at level 70).

Inductive AOrd : relation A :=
| A1_Ord : A1 <=A A1
| A2_Ord : A2 <=A A2
| A1_A2  : A1 <=A A2
where "a1 '<=A' a2" := (AOrd a1 a2).

Reserved Notation "b1 '<=B' b2" (at level 70).

Inductive BOrd : relation B :=
| B1_Ord : forall a1 a2,
    a1 <=A a2 -> B1 a1 <=B B1 a2
| B2_Ord :
  B2 <=B B2
| B1_B2  : forall a,
    B1 a <=B B2
where "b1 '<=B' b2" := (BOrd b1 b2).

Finally, I introduce a concept of reflexivity and prove that both of my relations are reflexive:

Definition reflexive {X : Type} (R : relation X) :=
  forall a : X, R a a.

Adding and removing hints in the core database implicitly is deprecated. Please specify a hint database. [implicit-core-hint-db,deprecated]
The default value for hint locality is currently "local" in a section and "global" otherwise, but is scheduled to change in a future release. For the time being, adding hints outside of sections without specifying an explicit locality is therefore deprecated. It is recommended to use "export" whenever possible. [deprecated-hint-without-locality,deprecated]

reflexive AOrd

reflexive AOrd
a: A

a <=A a
induction a; auto. Qed.
Adding and removing hints in the core database implicitly is deprecated. Please specify a hint database. [implicit-core-hint-db,deprecated]
The default value for hint locality is currently "local" in a section and "global" otherwise, but is scheduled to change in a future release. For the time being, adding hints outside of sections without specifying an explicit locality is therefore deprecated. It is recommended to use "export" whenever possible. [deprecated-hint-without-locality,deprecated]

reflexive BOrd

reflexive BOrd
b: B

b <=B b
induction b; auto. Qed.

Both proofs are finished with auto tactic, with the first proof crucially relying on Hint Constructors and the second one additionally on Hint Resolve AOrd_reflexive being added to hint database.

An ugly thing about the code above is having a separate notation for ordering relation for A and B data types. I'd like to be able to uniformly use <= everywhere. This answer provides a solution to the problem: use type classes. So I introduce a type class for ordering and redefine my ordering relations to use this new notation:

Class OrderR (T : Type) := orderR : relation T.
Notation "x '<=' y" := (orderR x y) (at level 70).

Inductive AOrd : OrderR A :=
| A1_Ord : A1 <= A1
| A2_Ord : A2 <= A2
| A1_A2  : A1 <= A2.

Inductive BOrd `{OrderR A} : OrderR B :=
| B1_Ord : forall a1 a2,
    a1 <= a2 -> B1 a1 <= B1 a2
| B2_Ord :
  B2 <= B2
| B1_B2  : forall a,
    B1 a <= B2.

Adding and removing hints in the core database implicitly is deprecated. Please specify a hint database. [implicit-core-hint-db,deprecated]
The default value for hint locality is currently "local" in a section and "global" otherwise, but is scheduled to change in a future release. For the time being, adding hints outside of sections without specifying an explicit locality is therefore deprecated. It is recommended to use "export" whenever possible. [deprecated-hint-without-locality,deprecated]

But now proof automation breaks! For example:


reflexive AOrd

reflexive AOrd
a: A

AOrd a a

AOrd A1 A1

AOrd A2 A2

leaves me with a goal:

2 subgoals ============================ AOrd A1 A1 subgoal 2 is: AOrd A2 A2

that auto no longer solves despite AOrd constructors being in hint database. I can solve the goal with constructor though:


reflexive AOrd

reflexive AOrd
a: A

AOrd a a
induction a; constructor. Qed.

More problems arise in second proof. After doing:

H: OrderR A

reflexive BOrd
H: OrderR A

reflexive BOrd
H: OrderR A
b: B

BOrd b b
H: OrderR A
a: A

a <= a

I am left with goal:

1 subgoal H : OrderR A a : A ============================ a <= a

Again, auto no longer solves this goal. Even apply AOrd_reflexive does not work.

My question is: is it possible to have a uniform notation by relying on type classes and maintain benefits of proof automation? Or is there a different solution to having a uniform notation for various data types.

Answer (eponier)

A solution that does not involve typeclasses is to take advantage of the scope mechanism of Coq.

Inductive A :=
| A1
| A2.

Inductive B :=
| B1 : A -> B
| B2.

Definition relation (X : Type) := X -> X -> Prop.

Reserved Notation "a1 '<=' a2" (at level 70).

Declaring a scope implicitly is deprecated; use in advance an explicit "Declare Scope a_scope.". [undeclared-scope,deprecated]
Declaring a scope implicitly is deprecated; use in advance an explicit "Declare Scope a_scope.". [undeclared-scope,deprecated]
Delimit Scope a_scope with a.
Declaring a scope implicitly is deprecated; use in advance an explicit "Declare Scope b_scope.". [undeclared-scope,deprecated]
Declaring a scope implicitly is deprecated; use in advance an explicit "Declare Scope b_scope.". [undeclared-scope,deprecated]
Delimit Scope b_scope with b. Definition reflexive {X : Type} (R : relation X) := forall a : X, R a a.
Adding and removing hints in the core database implicitly is deprecated. Please specify a hint database. [implicit-core-hint-db,deprecated]
The default value for hint locality is currently "local" in a section and "global" otherwise, but is scheduled to change in a future release. For the time being, adding hints outside of sections without specifying an explicit locality is therefore deprecated. It is recommended to use "export" whenever possible. [deprecated-hint-without-locality,deprecated]

reflexive AOrd

reflexive AOrd
a: A

(a <= a)%a
induction a; auto. Qed.
Adding and removing hints in the core database implicitly is deprecated. Please specify a hint database. [implicit-core-hint-db,deprecated]
The default value for hint locality is currently "local" in a section and "global" otherwise, but is scheduled to change in a future release. For the time being, adding hints outside of sections without specifying an explicit locality is therefore deprecated. It is recommended to use "export" whenever possible. [deprecated-hint-without-locality,deprecated]

reflexive BOrd

reflexive BOrd
b: B

(b <= b)%b
induction b; auto. Qed.

Answer (Jason Gross)

The issue is that your hints are set to trigger on, e.g., @orderR _ AOrd A1 A2, not AOrd A1 A2. So the automation never sees the pattern it's looking for, and never triggers the hints. Here are two solutions:

  1. You can adjust the type of your constructors when adding them to the hint database, so that they trigger when you want them to:

    Adding and removing hints in the core database implicitly is deprecated. Please specify a hint database. [implicit-core-hint-db,deprecated]
    The default value for hint locality is currently "local" in a section and "global" otherwise, but is scheduled to change in a future release. For the time being, adding hints outside of sections without specifying an explicit locality is therefore deprecated. It is recommended to use "export" whenever possible. [deprecated-hint-without-locality,deprecated]
    Declaring arbitrary terms as hints is fragile; it is recommended to declare a toplevel constant instead [fragile-hint-constr,automation]
    Declaring arbitrary terms as hints is fragile; it is recommended to declare a toplevel constant instead [fragile-hint-constr,automation]
    Declaring arbitrary terms as hints is fragile; it is recommended to declare a toplevel constant instead [fragile-hint-constr,automation]
    Adding and removing hints in the core database implicitly is deprecated. Please specify a hint database. [implicit-core-hint-db,deprecated]
    The default value for hint locality is currently "local" in a section and "global" otherwise, but is scheduled to change in a future release. For the time being, adding hints outside of sections without specifying an explicit locality is therefore deprecated. It is recommended to use "export" whenever possible. [deprecated-hint-without-locality,deprecated]
    Declaring arbitrary terms as hints is fragile; it is recommended to declare a toplevel constant instead [fragile-hint-constr,automation]
    Declaring arbitrary terms as hints is fragile; it is recommended to declare a toplevel constant instead [fragile-hint-constr,automation]
    Declaring arbitrary terms as hints is fragile; it is recommended to declare a toplevel constant instead [fragile-hint-constr,automation]
  2. You can define "folding" lemmas that convert the types, and add those to the database:

    Definition fold_AOrd a1 a2 (v : a1 <= a2) : AOrd a1 a2 := v.
    Definition fold_BOrd `{OrderR A} (a1 a2 : B) (v : a1 <= a2) : BOrd a1 a2 := v.
    
    Adding and removing hints in the core database implicitly is deprecated. Please specify a hint database. [implicit-core-hint-db,deprecated]
    The default value for hint locality is currently "local" in a section and "global" otherwise, but is scheduled to change in a future release. For the time being, adding hints outside of sections without specifying an explicit locality is therefore deprecated. It is recommended to use "export" whenever possible. [deprecated-hint-without-locality,deprecated]

Q: Thanks Jason. I'm afraid your solution does not work for me. Folding lemmas don't seem to change anything. Adjusting type of constructors works when proving AOrd_reflexive but in the proof of BOrd_reflexive it is still not possible to prove a <= a from AOrd_reflexive.