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.
Hint Constructors AOrd BOrd.
Theorem AOrd_reflexive : reflexive AOrd.
Proof.
intro a. induction a; auto.
Qed.
Hint Resolve AOrd_reflexive.
Theorem BOrd_reflexive : reflexive BOrd.
Proof.
intro 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.
Hint Constructors AOrd BOrd.
But now proof automation breaks! For example:
Theorem AOrd_reflexive : reflexive AOrd.
Proof.
intro a. induction a.
leaves me with a goal:
2 subgoals, subgoal 1 (ID 32)
─────────────────────────────────────────────────────
AOrd A1 A1
that auto
no longer solves despite AOrd
constructors being in hint database. I can solve the goal with constructor
though:
Theorem AOrd_reflexive : reflexive AOrd.
Proof.
intro a. induction a; constructor.
Qed.
More problems arise in second proof. After doing:
Theorem BOrd_reflexive `{OrderR A} : reflexive BOrd.
Proof.
intro b. induction b. constructor.
I am left with goal:
2 subgoals, subgoal 1 (ID 40)
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.
A solution that does not involve typeclasses is to take advantage of the scope mechanism of Coq.