Section Nth'.
(* In this implementation of [nth_error], instead of encoding an option to the output tape, we use the finite parameter to indicate whether the result is [Some] or [None]. The advantage is that the client doesn't have to add the option to its alphabet. *)
Variable (sig sigX : finType) (X : Type) (cX : codable sigX X).
(* Hypothesis (defX: inhabitedC sigX). *)
Variable (retr1 : Retract (sigList sigX) sig) (retr2 : Retract sigNat sig).
Local Instance retr_X_list' : Retract sigX sig := ComposeRetract retr1 (Retract_sigList_X _).
(* Check _ : codable sig (list X). *)
(* Check _ : codable sig nat. *)
Definition Nth'_Step_size {sigX X : Type} {cX : codable sigX X} (n : nat) (l : list X) : Vector.t (nat -> nat) 3 :=
match n, l with
| S n', x :: l' =>
[| CaseList_size0 x; S; CaseList_size1 x >> Reset_size x|]
| 0, x :: x' =>
[|fun s0 => CaseList_size0 x s0; id; fun s2 => CaseList_size1 x s2|]
| 0, nil => [|id; id; id|]
| S n', nil => [|id; fun s1 => S s1; id|]
end.
Definition Nth'_Step : pTM sig^+ (option bool) 3 :=
If (LiftTapes (ChangeAlphabet CaseNat _) [|Fin1|])
(If (LiftTapes (ChangeAlphabet (CaseList sigX) _) [|Fin0; Fin2|]) (* n = S n' *)
(Return (LiftTapes (Reset _) [|Fin2|]) None) (* l = x :: l'; continue *)
(Return Nop (Some false))) (* l = nil; return false *)
(Relabel (LiftTapes (ChangeAlphabet (CaseList sigX) _) [|Fin0; Fin2|]) Some) (* n = 0 *)
.
Definition Nth'_Step_steps {sigX X : Type} {cX : codable sigX X} (l : list X) (n : nat) :=
match n, l with
| S n', x :: l' =>
2 + CaseNat_steps + CaseList_steps_cons x + Reset_steps x
| S n', nil =>
2 + CaseNat_steps + CaseList_steps_nil
| O, x :: l' =>
1 + CaseNat_steps + CaseList_steps_cons x
| O, nil =>
1 + CaseNat_steps + CaseList_steps_nil
end.
Definition Nth'_Step_steps_CaseList (xs : list X) :=
match xs with
| x :: xs' => 1 + CaseList_steps_cons x + Reset_steps x
| nil => 1 + CaseList_steps_nil
end.
Fixpoint Nth'_Loop_size {sigX X : Type} {cX : codable sigX X} (n : nat) (l : list X) {struct n} : Vector.t (nat -> nat) 3 :=
match n, l with
| S n', x :: l' => Nth'_Step_size n l >>> Nth'_Loop_size n' l'
| _, _ => Nth'_Step_size n l
end.
Definition Nth'_Loop := While Nth'_Step.
Fixpoint Nth'_Loop_steps {sigX X : Type} {cX : codable sigX X} (l : list X) (n : nat) { struct l } :=
match n, l with
| S n', x :: l'  => S (Nth'_Step_steps l n) + Nth'_Loop_steps l' n' (* continue *)
| S n', nil => Nth'_Step_steps l n (* return *)
| O, x :: l' => Nth'_Step_steps l n (* return *)
| O, nil => Nth'_Step_steps l n (* only [CaseNat] and [If] *)
end.
(* We don't want to save, but reset, [n]. *)
Definition Nth' : pTM sig^+ bool 4 :=
LiftTapes (CopyValue _) [|Fin0; Fin3|];; (* Save l (on t0) to t3 *)
If (LiftTapes (Nth'_Loop) [|Fin3; Fin1; Fin2|]) (* Execute the loop with the copy of l *)
(Return (LiftTapes (Reset _) [|Fin3|];; (* Reset the copy of [l] *)
LiftTapes (Reset _) [|Fin1|] (* Reset [n] *)
) true)
(Return (LiftTapes (Reset _) [|Fin3|];; (* Reset the copy of [l] *)
LiftTapes (Reset _) [|Fin1|] (* Reset [n] *)
) false)
.
Definition Nth'_size {sigX X : Type} {cX : codable sigX X} (l : list X) (n : nat) :=
[| id;
(Nth'_Loop_size n l)[@Fin1] >> Reset_size (n - (S (length l)));
(Nth'_Loop_size n l)[@Fin2];
CopyValue_size l >> (Nth'_Loop_size n l)[@Fin0] >> Reset_size (skipn (S n) l)
|].
Definition Nth'_steps {sigX X : Type} {cX : codable sigX X} (l : list X) (n : nat) :=
3 + CopyValue_steps l + Nth'_Loop_steps l n + Reset_steps (skipn (S n) l) + Reset_steps (n - S (length l)).

Lemma Nth'_SpecT_size (xs : list X) (n : nat) (ss : Vector.t nat 4) :
TripleT
(≃≃([],withSpace ([|Contains _ xs; Contains _ n; Void; Void|]) ss))
(Nth'_steps xs n) Nth'
(fun yout =>
≃≃([yout = match nth_error xs n with None => false | _ => true end],
withSpace match nth_error xs n with
| Some x => [|Contains _ xs; Void; Contains _ x;Void|]
| None  => [|Contains _ xs; Void; Void;Void|]
end
(appSize (Nth'_size xs n) ss))).