Parametric Arity Functions
(* SETOID FUNCTIONS WITH PARAMETRIC ARITY *)
(* by Venanzio Capretta *)
(* Coq version 6.2.3 *)
Require Export Setoids.
Require Export Finite_Sets.
(* We want to define types of functions whose arity is given by parameters.
The arity will be given by a natural number n and a family of n setoids
A : (Finite n) -> Setoid.
*)
(* There are many ways of representing such a type. Each representation has
some advantages, so we will define operators to commute from one
representation to an other.
*)
(* First representation: curried functions. *)
Fixpoint
Curry_setoid_function [n:nat]
: ((Finite n) -> Setoid) -> Setoid -> Setoid
:=
<[n:nat]((Finite n) -> Setoid) -> Setoid -> Setoid>
Cases n of
O => [A][B]B
| (S n') => [A][B](S_Fun (A (fin_zero n'))
(Curry_setoid_function n'
[i](A (fin_succ i))
B
)
)
end.
(* Second representation: functions with a functional argument.
The arguments of the function are given by a function on a finite set:
f : (i:(Finite n))(A i) -> B.
*)
Section Functional_Argument_Function.
Variable n : nat.
Variable A : (Finite n) -> Setoid.
Variable B : Setoid.
(* First of all we must transform the Set (i:(Finite n))(A i) in a setoid
with the extensional equality.
*)
Definition
ff_eq :
(relation (i:(Finite n))(A i))
:=[f,g](i : (Finite n)) (f i) [=] (g i).
Lemma
ff_eq_equivalence : (Equiv ff_eq).
Definition
FF_setoid : Setoid :=
(setoid ff_eq_equivalence).
(* Our second representation is then a function from this setoid to B. *)
Definition
Fun_arg_function : Setoid := (S_Fun FF_setoid B).
End Functional_Argument_Function.
(* The third representation takes an n-tuple as an argument:
f : A0 X ... X A(n-1) -> B.
*)
(* First of all we must define the n-fold product of setoids. *)
(* Special case for n=1 to avoid a spurious argoument of type S_unit. *)
Definition
S_multi_prod_step
: (n:nat)
(((Finite n) -> Setoid) -> Setoid) ->
((Finite (S n)) -> Setoid) -> Setoid
:=
[n:nat]
<[n:nat](((Finite n) -> Setoid) -> Setoid) ->
((Finite (S n)) -> Setoid) -> Setoid>
Cases n of
O => [_][A](A (fin_zero O))
| (S n') => [n_pr][A](S_prod (A (fin_zero (S n')))
(n_pr [i](A (fin_succ i)))
)
end.
Fixpoint
S_multi_prod [n:nat] : ((Finite n) -> Setoid) -> Setoid :=
<[n:nat]((Finite n) -> Setoid) -> Setoid>
Cases n of
O => [A]S_unit
| (S n') => (S_multi_prod_step n' (S_multi_prod n'))
end.
(* Our third representation is then a function with this setoid as domain. *)
Definition
Tuple_arg_function
: (n:nat)((Finite n)->Setoid) -> Setoid -> Setoid
:= [n,A,B](S_Fun (S_multi_prod n A) B).
(* Now we need to define operators to commute between these representations. *)
(* Conversion from the first (curried function) to the second (function
argument) representation.
*)
(* Case n=0. *)
Section Conversion12_Case0.
Variable A : (Finite O) -> Setoid.
Variable B : Setoid.
Variable f : (Curry_setoid_function O A B). (* == B *)
Local conv12_case0_fun : (FF_setoid O A) -> B :=
[args]f.
Remark conv12_case0_well_defined
: (fun_well_defined conv12_case0_fun).
Definition
conv12_case0 : (Fun_arg_function O A B) :=
(setoid_function conv12_case0_well_defined).
End Conversion12_Case0.
Lemma
conv12_case0_well_defined :
(A : (Finite O) -> Setoid)(B : Setoid)
(fun_well_defined (conv12_case0 A B)).
Definition
curry_to_fun_arg_0
: (A : (Finite O) -> Setoid)(B : Setoid)
(S_Fun (Curry_setoid_function O A B) (Fun_arg_function O A B))
:=
[A][B](setoid_function (conv12_case0_well_defined A B)).
Section Conversion12_CaseS.
Variable n : nat.
Variable curry_to_fun_arg_IH :
(A : (Finite n) -> Setoid)(B : Setoid)
(S_Fun (Curry_setoid_function n A B) (Fun_arg_function n A B)).
Variable A : (Finite (S n)) -> Setoid.
Variable B : Setoid.
Local A' : (Finite n) -> Setoid := [i](A (fin_succ i)).
Local conv12_IH :
(S_Fun (Curry_setoid_function n A' B) (Fun_arg_function n A' B))
:= (curry_to_fun_arg_IH A' B).
Section Conv12_CaseS_function.
Variable f : (Curry_setoid_function (S n) A B).
(* == A0 => (Curry_setoid_function n A' B) *)
Local one_less_arg : (FF_setoid (S n) A) -> (Fun_arg_function n A' B) :=
[args](conv12_IH (f (args (fin_zero n)))).
Remark one_less_arg_well_defined
: (fun_well_defined one_less_arg).
Local conv12_caseS_fun : (FF_setoid (S n) A) -> B :=
[args]( (one_less_arg args) [i](args (fin_succ i)) ).
Remark conv12_caseS_well_defined
: (fun_well_defined conv12_caseS_fun).
Definition
conv12_caseS : (S_Fun (FF_setoid (S n) A) B) :=
(setoid_function conv12_caseS_well_defined).
End Conv12_CaseS_function.
Lemma
conv12_caseS_well_defined :
(fun_well_defined conv12_caseS).
Definition
curry_to_fun_arg_S :
(S_Fun (Curry_setoid_function (S n) A B) (Fun_arg_function (S n) A B))
:=
(setoid_function conv12_caseS_well_defined).
End Conversion12_CaseS.
(* Here is the operator that covert a function in the first representation
into the second representation.
*)
Fixpoint
curry_to_fun_arg [n : nat]
: (A : (Finite n) -> Setoid)(B : Setoid)
(S_Fun (Curry_setoid_function n A B) (Fun_arg_function n A B))
:=
<[n:nat](A : (Finite n) -> Setoid)(B : Setoid)
(S_Fun (Curry_setoid_function n A B) (Fun_arg_function n A B))>
Cases n of
O => curry_to_fun_arg_0
| (S n') => (curry_to_fun_arg_S n' (curry_to_fun_arg n'))
end.
(* Conversion from the second (function argument) to the first
(curried function) representation.
*)
(* Case n=0. *)
Section Conversion21_Case0.
Variable A : (Finite O) -> Setoid.
Variable B : Setoid.
Local conv21_case0_fun :
(Fun_arg_function O A B) -> (Curry_setoid_function O A B)
:=
[f](f [i](empty_finite_O (A i) i)).
Remark conv21_case0_well_defined
: (fun_well_defined conv21_case0_fun).
Definition
fun_arg_to_curry_0 :
(S_Fun (Fun_arg_function O A B) (Curry_setoid_function O A B))
:=
(setoid_function conv21_case0_well_defined).
End Conversion21_Case0.
(* Case n = (S n'). *)
(* In this case we have first to give a preliminary definition:
suppose we have a function f : (FF_setoid n [i](A (succ i)))
and an element a0 : (A O).
We then want to define a new function
f' : (FF_setoid (S n) A)
such that (f' O) = a0 and (f' (succ i)) = (f i).
*)
Section Finite_Function_Succ.
Variable n : nat.
Variable A : (Finite (S n)) -> Setoid.
Variable f : (FF_setoid n [i](A (fin_succ i))).
Variable a0 : (A (fin_zero n)).
(* First of all we define the function by cases on the argument. *)
Definition
f_cases : (m : nat)(p : (gt (S n) m))(A (fin_inj p)) :=
[m:nat]
<[m:nat](p : (gt (S n) m))(A (fin_inj p))>
Cases m of
O => [_]a0
| (S m') => [p](eq_rec (Finite (S n)) ? A
(f (fin_inj (gt_S_n m' n p)))
?
(fin_succ_inj p)
)
end.
Definition
ff_add_new_argument : (FF_setoid (S n) A) :=
[i](eq_rec (Finite (S n)) ? A
(f_cases (fin_extr i) (fin_extr_gt i))
?
(fin_section i)
).
End Finite_Function_Succ.
Lemma
f_cases_well_defined1 :
(n : nat)(A : (Finite (S n))->Setoid)
(f1, f2 : (FF_setoid n [i:(Finite n)](A (fin_succ i))))
f1 [=] f2 ->
(a0 : (A (fin_zero n)))
(m:nat)(p:(gt (S n) m))
(f_cases n A f1 a0 m p) [=] (f_cases n A f2 a0 m p).
Lemma
ff_add_new_argument_well_defined1 :
(n : nat)(A : (Finite (S n))->Setoid)(a0 : (A (fin_zero n)))
(fun_well_defined [f](ff_add_new_argument n A f a0)).
Lemma
f_cases_well_defined2 :
(n : nat)(A : (Finite (S n))->Setoid)
(f : (FF_setoid n [i:(Finite n)](A (fin_succ i))))
(a1, a2 : (A (fin_zero n))) a1 [=] a2 ->
(m:nat)(p:(gt (S n) m))
(f_cases n A f a1 m p) [=] (f_cases n A f a2 m p).
Lemma
ff_add_new_argument_well_defined2 :
(n : nat)(A : (Finite (S n))->Setoid)
(f : (FF_setoid n [i:(Finite n)](A (fin_succ i))))
(fun_well_defined [a0](ff_add_new_argument n A f a0)
).
(* Now we ca construct the recursive step. *)
Section Conversion21_CaseS.
Variable n : nat.
Variable fun_arg_to_curry_IH :
(A : (Finite n) -> Setoid)(B : Setoid)
(S_Fun (Fun_arg_function n A B) (Curry_setoid_function n A B)).
Variable A : (Finite (S n)) -> Setoid.
Variable B : Setoid.
Local A' : (Finite n) -> Setoid := [i](A (fin_succ i)).
Section Conv21_CaseS_function.
Variable f : (Fun_arg_function (S n) A B).
Local f' : (a0 : (A (fin_zero n)))(FF_setoid n A') -> B :=
[a0][args : (FF_setoid n A')](f (ff_add_new_argument n A args a0)).
Remark f'_well_defined1 :
(a0 : (A (fin_zero n)))(h1, h2 : (FF_setoid n A'))
h1 [=] h2 -> (f' a0 h1) [=] (f' a0 h2).
Local f'_rec : (a0 : (A (fin_zero n)))(Fun_arg_function n A' B) :=
[a0](setoid_function (f'_well_defined1 a0)).
Local f_curry : (a0 : (A (fin_zero n)))(Curry_setoid_function n A' B) :=
[a0]((fun_arg_to_curry_IH A' B) (f'_rec a0)).
Remark f_curry_well_defined :
(fun_well_defined f_curry).
Definition
conv21_caseS : (Curry_setoid_function (S n) A B) :=
(setoid_function f_curry_well_defined).
End Conv21_CaseS_function.
Lemma
conv21_caseS_well_defined :
(fun_well_defined conv21_caseS).
Definition
fun_arg_to_curry_S :
(S_Fun (Fun_arg_function (S n) A B) (Curry_setoid_function (S n) A B))
:=
(setoid_function conv21_caseS_well_defined).
End Conversion21_CaseS.
(* Here is the operator that covert a function in the second representation
into the first representation.
*)
Fixpoint
fun_arg_to_curry [n : nat]
: (A : (Finite n) -> Setoid)(B : Setoid)
(S_Fun (Fun_arg_function n A B) (Curry_setoid_function n A B))
:=
<[n:nat](A : (Finite n) -> Setoid)(B : Setoid)
(S_Fun (Fun_arg_function n A B) (Curry_setoid_function n A B))>
Cases n of
O => fun_arg_to_curry_0
| (S n') => (fun_arg_to_curry_S n' (fun_arg_to_curry n'))
end.
(* Proof that fun_arg_to_curry is left inverse of curry_to_fun_arg. *)
Axiom fun_arg_inv_curry :
(n : nat)(A : (Finite n) -> Setoid)(B : Setoid)
(f : (Curry_setoid_function n A B))
f [=] ((fun_arg_to_curry n A B) ((curry_to_fun_arg n A B) f)).
(* Proof that curry_to_fun_arg is left inverse of fun_arg_to_curry. *)
Axiom curry_inv_fun_arg :
(n : nat)(A : (Finite n) -> Setoid)(B : Setoid)
(f : (Fun_arg_function n A B))
f [=] ((curry_to_fun_arg n A B) ((fun_arg_to_curry n A B) f)).
(* STILL TO BE DONE:
1) Proof that the two operators are inverse of one another;
2) Defined operators for the third representation.
*)
25/02/99, 14:36