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.

Lemma eval_compose_spec (n : arity) (m : arity) (gs : Vector.t (naryFun n) m) (h : naryFun m) (xs : Vector.t nat n) (ys : Vector.t nat m) (z : nat)
(gs_spec : V.map (eval_vec xs) gs = ys)
(h_spec : eval_vec ys h = z)
: eval_vec xs (eval_compose gs h) = z.