Typeclass-based setoids, tactics and standard instances.

Author: Matthieu Sozeau Institution: LRI, CNRS UMR 8623 - University Paris Sud

Set Implicit Arguments.

Require Import Coq.Program.Program.

Require Import Relation_Definitions.
Require Export Coq.Classes.RelationClasses.
Require Export Coq.Classes.Morphisms.

A setoid wraps an equivalence.

Class Setoid A := {
equiv : relation A ;
setoid_equiv :> Equivalence equiv }.

Shortcuts to make proof search easier.

Definition setoid_refl `(sa : Setoid A) : Reflexive equiv.

Definition setoid_sym `(sa : Setoid A) : Symmetric equiv.

Definition setoid_trans `(sa : Setoid A) : Transitive equiv.

Standard setoids.

Program Instance iff_setoid : Setoid Prop :=
{ equiv := iff ; setoid_equiv := iff_equivalence }.

Overloaded notations for setoid equivalence and inequivalence. Not to be confused with eq and =.
Subset objects should be first coerced to their underlying type, but that notation doesn't work in the standard case then.

Notation " x == y " := (equiv x y) (at level 70, no associativity) : type_scope.

Notation " x =/= y " := (complement equiv x y) (at level 70, no associativity) : type_scope.

Use the clsubstitute command which substitutes an equality in every hypothesis.

Ltac clsubst H :=
lazymatch type of H with
?x == ?y => substitute H ; clear H x
end.

Ltac clsubst_nofail :=
match goal with
| [ H : ?x == ?y |- _ ] => clsubst H ; clsubst_nofail
| _ => idtac
end.

subst* will try its best at substituting every equality in the goal.

Tactic Notation "clsubst" "*" := clsubst_nofail.

Lemma nequiv_equiv_trans : forall `{Setoid A} (x y z : A), x =/= y -> y == z -> x =/= z.

Lemma equiv_nequiv_trans : forall `{Setoid A} (x y z : A), x == y -> y =/= z -> x =/= z.

Ltac setoid_simplify_one :=
match goal with
| [ H : (?x == ?x)%type |- _ ] => clear H
| [ H : (?x == ?y)%type |- _ ] => clsubst H
| [ |- (?x =/= ?y)%type ] => let name:=fresh "Hneq" in intro name
end.

Ltac setoid_simplify := repeat setoid_simplify_one.

Ltac setoidify_tac :=
match goal with
| [ s : Setoid ?A, H : ?R ?x ?y |- _ ] => change R with (@equiv A R s) in H
| [ s : Setoid ?A |- context C [ ?R ?x ?y ] ] => change (R x y) with (@equiv A R s x y)
end.

Ltac setoidify := repeat setoidify_tac.

Every setoid relation gives rise to a morphism, in fact every partial setoid does.

Program Instance setoid_morphism `(sa : Setoid A) : Proper (equiv ++> equiv ++> iff) equiv :=
proper_prf.

Program Instance setoid_partial_app_morphism `(sa : Setoid A) (x : A) : Proper (equiv ++> iff) (equiv x) :=
proper_prf.

Partial setoids don't require reflexivity so we can build a partial setoid on the function space.

Class PartialSetoid (A : Type) :=
{ pequiv : relation A ; pequiv_prf :> PER pequiv }.

Overloaded notation for partial setoid equivalence.

Infix "=~=" := pequiv (at level 70, no associativity) : type_scope.

Reset the default Program tactic.

Obligation Tactic := program_simpl.