From Undecidability.Shared.Libs.PSL Require Export BasicDefinitions.
From Undecidability.Shared.Libs.PSL Require Import Bijection.
(* ** Formalisation of finite types using canonical structures and type classes *)
(* * Definition of finite Types *)
Class finTypeC  (type:eqType) : Type :=
FinTypeC {
enum: list type;
enum_ok: forall x: type, count enum x = 1
}.
Structure finType : Type :=
FinType
{
type:> eqType;
class: finTypeC type
}.
Arguments FinType type {class}.
Existing Instance class | 0.
(* This is a hack to work-around a problem with a class of hacks *)
Hint Extern 5 (finTypeC (EqType ?x)) => unfold x : typeclass_instances.
Canonical Structure finType_CS (X : Type) {p : eq_dec X} {class : finTypeC (EqType X)} : finType := FinType (EqType X).
(* Print the base type of [finType] in the Canonical Structure. *)
Arguments finType_CS (X) {_ _}.
Definition elem (F: finType) := @enum (type F) (class F).
Hint Unfold elem : core.
Hint Unfold class : core.
Hint Resolve elem_spec : core.
Hint Resolve enum_ok : core.
Hint Resolve allSub : core.
Instance finType_forall_dec (X: finType) (p: X -> Prop): (forall x, dec (p x)) -> dec (forall x, p x).
Instance finType_exists_dec (X:finType) (p: X -> Prop) : (forall x, dec (p x)) -> dec (exists x, p x).
Definition finType_cc (X: finType) (p: X -> Prop) (D: forall x, dec (p x)) : (exists x, p x) -> {x | p x}.
(* Index is an injective function *)
Fixpoint  getPosition {E: eqType} (A: list E) x := match A with
| nil => 0
| cons x' A' => if Dec (x=x') then 0 else 1 + getPosition A' x end.
Definition pos_def (X : eqType) (x : X) A n :=  match pos x A with None => n | Some n => n end.
Definition index {F: finType} (x:F) := getPosition (elem F) x.
unfold index, elem, enum.
destruct F as [[X E] [A all_A]];cbn.
pose proof (getPosition_correct x A) as H.
destruct Dec. auto. apply notInZero in n. now setoid_rewrite all_A in n.
Qed.

Lemma injective_index (A: finType) (x1 x2 : A) : index x1 = index x2 -> x1 = x2.