Section PRIMITIVE_RECURSION. (* Reference: "https://github.com/princeton-vl/CoqGym/blob/master/coq_projects/goedel/primRec.v" *)
#[local] Open Scope program_scope.
Let arity : Set := nat.
Fixpoint naryFun (n : arity) : Set :=
match n with
| O => nat
| S n' => nat -> naryFun n'
end.
Fixpoint naryRel (n : arity) : Type :=
match n with
| O => Prop
| S n' => nat -> naryRel n'
end.
Fixpoint eval_vec {n : arity} (xs : Vector.t nat n) : naryFun n -> nat :=
match xs with
| VNil => id
| VCons n' x xs' => fun f => eval_vec xs' (f x)
end.
Fixpoint eval_const {n : arity} (m : nat) : naryFun n :=
match n with
| O => m
| S n' => const (eval_const m)
end.
Fixpoint eval_proj {n : arity} (i : Fin.t n) : naryFun n :=
match i with
| FZ => eval_const
| FS i' => const (eval_proj i')
end.
Fixpoint eval_vec_1 {n : arity} {m : arity} (x : nat) (xs : Vector.t (naryFun (S n)) m) : Vector.t (naryFun n) m :=
match xs with
| VNil => VNil
| VCons m' f xs' => VCons m' (f x) (eval_vec_1 x xs')
end.
Fixpoint eval_compose {n : arity} {m : arity} : Vector.t (naryFun n) m -> naryFun m -> naryFun n :=
match n with
| O => fun xs => eval_vec xs
| S n' => fun xs => fun f => fun x => eval_compose (eval_vec_1 x xs) f
end.
Fixpoint eval_compose_2 {n : arity} : naryFun n -> naryFun (S n) -> naryFun n :=
match n with
| O => fun x => fun f => f x
| S n' => fun f => fun g => fun a => eval_compose_2 (f a) (fun x => g x a)
end.

Lemma eval_compose_2_spec (n : arity) (g : naryFun n) (h : naryFun (S n)) (xs : Vector.t nat n) (a : nat) (z : nat)
(g_spec : eval_vec xs g = a)
(h_spec : eval_vec (a :: xs) h = z)
: eval_vec xs (eval_compose_2 g h) = z.