(* A generic wrapper type *)
Canonical wrap T x := @Wrap T x.
Prenex Implicits unwrap wrap Wrap.
(* Syntax for defining auxiliary recursive function.          *)
(*  Usage:                                                    *)
(* Section FooDefinition.                                     *)
(* Variables (g1 : T1) (g2 : T2).  (globals)                  *)
(* Fixoint foo_auxiliary (a3 : T3) ... :=                     *)
(*        body, using [rec e3, ...] for recursive calls       *)
(* where "[ 'rec' a3 , a4 , ... ]" := foo_auxiliary.          *)
(* Definition foo x y .. := [rec e1, ...].                    *)
(* + proofs about foo                                         *)
(* End FooDefinition.                                         *)
Reserved Notation "[ 'rec' a0 ]"
(at level 0, format "[ 'rec'  a0 ]").
Reserved Notation "[ 'rec' a0 , a1 ]"
(at level 0, format "[ 'rec'  a0 ,  a1 ]").
Reserved Notation "[ 'rec' a0 , a1 , a2 ]"
(at level 0, format "[ 'rec'  a0 ,  a1 ,  a2 ]").
Reserved Notation "[ 'rec' a0 , a1 , a2 , a3 ]"
(at level 0, format "[ 'rec'  a0 ,  a1 ,  a2 ,  a3 ]").
Reserved Notation "[ 'rec' a0 , a1 , a2 , a3 , a4 ]"
(at level 0, format "[ 'rec'  a0 ,  a1 ,  a2 ,  a3 ,  a4 ]").
Reserved Notation "[ 'rec' a0 , a1 , a2 , a3 , a4 , a5 ]"
(at level 0, format "[ 'rec'  a0 ,  a1 ,  a2 ,  a3 ,  a4 ,  a5 ]").
Reserved Notation "[ 'rec' a0 , a1 , a2 , a3 , a4 , a5 , a6 ]"
(at level 0, format "[ 'rec'  a0 ,  a1 ,  a2 ,  a3 ,  a4 ,  a5 ,  a6 ]").
Reserved Notation "[ 'rec' a0 , a1 , a2 , a3 , a4 , a5 , a6 , a7 ]"
(at level 0,
format "[ 'rec'  a0 ,  a1 ,  a2 ,  a3 ,  a4 ,  a5 ,  a6 ,  a7 ]").
Reserved Notation "[ 'rec' a0 , a1 , a2 , a3 , a4 , a5 , a6 , a7 , a8 ]"
(at level 0,
format "[ 'rec'  a0 ,  a1 ,  a2 ,  a3 ,  a4 ,  a5 ,  a6 ,  a7 ,  a8 ]").
Reserved Notation "[ 'rec' a0 , a1 , a2 , a3 , a4 , a5 , a6 , a7 , a8 , a9 ]"
(at level 0,
format "[ 'rec'  a0 ,  a1 ,  a2 ,  a3 ,  a4 ,  a5 ,  a6 ,  a7 ,  a8 ,  a9 ]").
(* Definitions and notation for explicit functions with simplification,     *)
(* i.e., which simpl and /= beta expand (this is complementary to nosimpl). *)
Section SimplFun.
Variables aT rT : Type.
Variant simpl_fun := SimplFun of aT -> rT.
Definition fun_of_simpl f := fun x => let: SimplFun lam := f in lam x.
Coercion fun_of_simpl : simpl_fun >-> Funclass.
End SimplFun.
Notation "[ 'fun' : T => E ]" := (SimplFun (fun _ : T => E))
(at level 0,
format "'[hv' [ 'fun' :  T  => '/ '  E ] ']'") : fun_scope.
Notation "[ 'fun' x => E ]" := (SimplFun (fun x => E))
(at level 0, x ident,
format "'[hv' [ 'fun'  x  => '/ '  E ] ']'") : fun_scope.
Notation "[ 'fun' x : T => E ]" := (SimplFun (fun x : T => E))
(at level 0, x ident, only parsing) : fun_scope.
Notation "[ 'fun' x y => E ]" := (fun x => [fun y => E])
(at level 0, x ident, y ident,
format "'[hv' [ 'fun'  x  y  => '/ '  E ] ']'") : fun_scope.
Notation "[ 'fun' x y : T => E ]" := (fun x : T => [fun y : T => E])
(at level 0, x ident, y ident, only parsing) : fun_scope.
Notation "[ 'fun' ( x : T ) y => E ]" := (fun x : T => [fun y => E])
(at level 0, x ident, y ident, only parsing) : fun_scope.
Notation "[ 'fun' x ( y : T ) => E ]" := (fun x => [fun y : T => E])
(at level 0, x ident, y ident, only parsing) : fun_scope.
Notation "[ 'fun' ( x : xT ) ( y : yT ) => E ]" :=
(fun x : xT => [fun y : yT => E])
(at level 0, x ident, y ident, only parsing) : fun_scope.
(* For delta functions in eqtype.v. *)
Definition SimplFunDelta aT rT (f : aT -> aT -> rT) := [fun z => f z z].
(* Extensional equality, for unary and binary functions, including syntactic  *)
(* sugar.                                                                     *)
Section ExtensionalEquality.
Variables A B C : Type.
Definition eqfun (f g : B -> A) : Prop := forall x, f x = g x.
Definition eqrel (r s : C -> B -> A) : Prop := forall x y, r x y = s x y.

(* Specifications: *)
Lemma frefl f : eqfun f f. Proof. by []. Qed.
Lemma fsym f g : eqfun f g -> eqfun g f. Proof. by move=> eq_fg x. Qed.
Lemma ftrans f g h : eqfun f g -> eqfun g h -> eqfun f h.
Lemma bij_can_eq f' f'' : cancel f f' -> cancel f f'' -> f' =1 f''.
End Bijections.