Require Import Coq.Bool.Bool.
Require Import Coq.Classes.RelationClasses.
Require Import ExtLib.Tactics.Consider.

Set Implicit Arguments.
Set Strict Implicit.

Class CmpDec (T : Type) (equ : T -> T -> Prop) (ltu : T -> T -> Prop) : Type :=
{ cmp_dec : T -> T -> comparison }.

Class CmpDec_Correct T (equ ltu : T -> T -> Prop) (ED : CmpDec equ ltu) : Prop :=
{ cmp_dec_correct : forall x y : T, 
  match cmp_dec x y with
    | Eq => equ x y
    | Lt => ltu x y
    | Gt => ltu y x
  end }.

Inductive cmp_case (P Q R : Prop) : comparison -> Prop :=
| CaseEq : P -> cmp_case P Q R Eq
| CaseLt : Q -> cmp_case P Q R Lt
| CaseGt : R -> cmp_case P Q R Gt.

Section pair.
  Variable T U : Type.
  Variables eqt ltt : T -> T -> Prop.
  Variables equ ltu : U -> U -> Prop.

  Definition eq_pair (a b : T * U) : Prop :=
    eqt (fst a) (fst b) /\ equ (snd a) (snd b).

  Definition lt_pair (a b : T * U) : Prop :=
    ltt (fst a) (fst b) \/ (eqt (fst a) (fst b) /\ ltu (snd a) (snd b)).

  Variable cdt : CmpDec eqt ltt.
  Variable cdu : CmpDec equ ltu.

  Instance CmpDec_pair : CmpDec eq_pair lt_pair :=
  { cmp_dec := fun a b =>
    let '(al,ar) := a in
    let '(bl,br) := b in
    match cmp_dec al bl with
      | Eq => cmp_dec ar br 
      | x => x 
    end }.

  Variable cdtC : CmpDec_Correct cdt.
  Variable cduC : CmpDec_Correct cdu.
  Variable Symmetric_eqt : Symmetric eqt.

  Instance CmpDec_Correct_pair : CmpDec_Correct CmpDec_pair.
  Proof.
(* Goal: @CmpDec_Correct (prod T U) eq_pair lt_pair CmpDec_pair *)
    constructor. destruct x; destruct y; unfold eq_pair, lt_pair; simpl in *.
(* Goal: match match @cmp_dec T eqt ltt cdt t t0 with | Eq => @cmp_dec U equ ltu cdu u u0 | Lt => Lt | Gt => Gt end with | Eq => and (eqt t t0) (equ u u0) | Lt => or (ltt t t0) (and (eqt t t0) (ltu u u0)) | Gt => or (ltt t0 t) (and (eqt t0 t) (ltu u0 u)) end *)
    generalize (cmp_dec_correct t t0); destruct (cmp_dec t t0); simpl; intros; auto.
(* Goal: match @cmp_dec U equ ltu cdu u u0 with | Eq => and (eqt t t0) (equ u u0) | Lt => or (ltt t t0) (and (eqt t t0) (ltu u u0)) | Gt => or (ltt t0 t) (and (eqt t0 t) (ltu u0 u)) end *)
    generalize (cmp_dec_correct u u0); destruct (cmp_dec u u0); simpl; intros; auto.
  Qed.
End pair.

