(* There is nth_error in the Coq library, but it seems to return something in Type. *)
Fixpoint nth_option(A : Set)(ls : list A)(i : nat) :=
  match ls with 
    | nil => None
    | a :: ls' =>
      match i with
        | O => Some a
        | S i' =>
          nth_option ls' i'
          end
  end.

(* Specifications: *)
Theorem nth_option_app_Some : forall (A : Set)(ls1 ls2 : list A) i a, nth_option ls1 i = Some a -> nth_option (ls1 ++ ls2) i = Some a.
Theorem nth_option_Some_lt : forall (A : Set)(ls : list A) i a, nth_option ls i = Some a -> i < length ls.
Theorem nth_option_app_None : forall (A : Set)(ls1 ls2 : list A) i, nth_option ls1 i = None -> nth_option (ls1 ++ ls2) i = nth_option ls2 (i - length ls1).
Theorem nth_option_None_ge : forall (A : Set)(ls : list A) i, nth_option ls i = None -> i >= length ls.
Theorem skipn_S_eq : forall (A : Set)(ls : list A) n a, nth_option ls n = Some a -> skipn n ls = a :: (skipn (S n) ls).
Theorem nth_option_snd_split : forall (A B : Set)(ls : list (A * B)) n a b, nth_option ls n = Some (a, b) -> nth_option (snd (split ls)) n = Some b.
Theorem snd_split_map_eq : forall (A B C : Set)(ls : list A)(f : A -> B * C), snd (split (map f ls)) = map (fun p => snd (f p)) ls.
Theorem cons_ne : forall (A : Set)(eqda : eq_dec A)(a1 a2 : A)(ls1 ls2 : list A), ((a1 :: ls1) = (a2 :: ls2) -> False) -> (a1 <> a2) \/ (ls1 <> ls2).
Theorem map_ne_same_ex : forall (A B : Set)(f1 f2 : A -> B)(ls : list A), eq_dec B -> map f1 ls <> map f2 ls -> exists a, In a ls /\ f1 a <> f2 a.
Theorem list_pred_I_in : forall (A B : Set)(lsa : list A)(lsb : list B), length lsa = length lsb -> list_pred (fun a b => In a lsa /\ In b lsb) lsa lsb.
Theorem list_pred_fst_split_eq_l : forall (A B : Set)(a : list (A * B))(b : list A), list_pred (fun a0 b0 => fst a0 = b0) a b -> b = fst (split a).
Theorem list_pred_fst_split_flatten_eq_l : forall (A B : Set)(a : list (list (A * B)))(b : list (list A)), list_pred (list_pred (fun a0 b0 => fst a0 = b0)) a b -> flatten b = fst (split (flatten a)).
Theorem fold_add_const_mult : forall (A : Type)(ls : list A)(c : nat) init, (fold_left (fun acc _ => acc + c) ls init = (length ls) * c + init)%nat.
Theorem list_pred_snd_split_eq_l: forall (A B : Set) (a : list (B * A)) (b : list A), list_pred (fun (a0 : B * A) (b0 : A) => snd a0 = b0) a b -> b = snd (split a).
Theorem NoDup_snd_split_if : forall (A B : Type)(ls : list (A * B)), NoDup (snd (split ls)) -> NoDup ls.