(** * Preliminaries *)
(* Switch Coq into implicit argument mode *)
Global Set Implicit Arguments.
Global Unset Strict Implicit.
(* Load basic Coq libraries *)
Require Export Omega List Morphisms.
(* Inversion tactic *)
Ltac inv H := inversion H; subst; clear H.
(* Beteva destuct tactics *)
Tactic Notation "destruct" "_":=
match goal with
| [ |- context[match ?X with _ => _ end] ] => destruct X
| [ H : context[match ?X with _ => _ end] |- _ ] => destruct X
end.
Tactic Notation "destruct" "_" "eqn" ":" ident(E)   :=
match goal with
| [ |- context[match ?X with _ => _ end] ] => destruct X eqn:E
| [ H : context[match ?X with _ => _ end] |- _ ] => destruct X eqn:E
end.
Tactic Notation "destruct" "_" "eqn" ":" "_"   :=
let E := fresh "E" in
match goal with
| [ |- context[match ?X with _ => _ end] ] => destruct X eqn:E
| [ H : context[match ?X with _ => _ end] |- _ ] => destruct X eqn:E
end.
Tactic Notation "destruct" "*" :=
repeat destruct _.
Tactic Notation "destruct" "*" "eqn" ":" ident(E) :=
repeat (let E := fresh E in destruct _ eqn:E; try progress inv E); try now congruence.
Tactic Notation "destruct" "*" "eqn" ":" "_" := destruct * eqn:E.
(* ** Decidability *)
Definition dec (X : Prop) : Type := {X} + {~ X}.
Notation "'eq_dec' X" := (forall x y : X, dec (x=y)) (at level 70).
(* Register dec as a type class *)
Existing Class dec.
Definition decision (X : Prop) (D : dec X) : dec X := D.
Arguments decision X {D}.
Tactic Notation "decide" constr(p) :=
destruct (decision p).
Tactic Notation "decide" constr(p) "as" simple_intropattern(i) :=
destruct (decision p) as i.
(* Hints for auto concerning dec *)
Hint Unfold dec.
Hint Extern 4 =>
match goal with
| [  |- dec ?p ] => exact (decision p)
end.
(* Improves type class inference *)
Hint Extern 4 =>
match goal with
| [  |- dec ((fun _ => _) _) ] => simpl
end : typeclass_instances.
(* Regiseva instance rules for dec *)
Instance True_dec :  dec True :=
left I.
Instance False_dec :  dec False :=
right (fun A => A).
Instance impl_dec (X Y : Prop) :
dec X -> dec Y -> dec (X -> Y).

Lemma dec_prop_iff (X Y : Prop) :
(X <-> Y) -> dec X -> dec Y.