(** Extract the n-th element of a list, as [List.nth_error] does,
    but the index [n] is of type [Z]. *)

Fixpoint list_nth_z (A: Type) (l: list A) (n: Z) {struct l}: option A :=
  match l with
  | nil => None
  | hd :: tl => if zeq n 0 then Some hd else list_nth_z tl (Z.pred n)
  end.

(* Specifications: *)
Lemma list_nth_z_in: forall (A: Type) (l: list A) n x, list_nth_z l n = Some x -> In x l.
Lemma list_nth_z_map: forall (A B: Type) (f: A -> B) (l: list A) n, list_nth_z (List.map f l) n = option_map f (list_nth_z l n).
Lemma list_nth_z_range: forall (A: Type) (l: list A) n x, list_nth_z l n = Some x -> 0 <= n < list_length_z l.
Lemma incl_cons_inv: forall (A: Type) (a: A) (b c: list A), incl (a :: b) c -> incl b c.
Lemma incl_app_inv_l: forall (A: Type) (l1 l2 m: list A), incl (l1 ++ l2) m -> incl l1 m.
Lemma incl_app_inv_r: forall (A: Type) (l1 l2 m: list A), incl (l1 ++ l2) m -> incl l2 m.
Lemma incl_same_head: forall (A: Type) (x: A) (l1 l2: list A), incl l1 l2 -> incl (x::l1) (x::l2).
Lemma list_map_exten: forall (A B: Type) (f f': A -> B) (l: list A), (forall x, In x l -> f x = f' x) -> List.map f' l = List.map f l.
Lemma list_map_compose: forall (A B C: Type) (f: A -> B) (g: B -> C) (l: list A), List.map g (List.map f l) = List.map (fun x => g(f x)) l.
Lemma list_map_identity: forall (A: Type) (l: list A), List.map (fun (x:A) => x) l = l.
Lemma list_map_nth: forall (A B: Type) (f: A -> B) (l: list A) (n: nat), nth_error (List.map f l) n = option_map f (nth_error l n).
Lemma list_length_map: forall (A B: Type) (f: A -> B) (l: list A), List.length (List.map f l) = List.length l.
Lemma list_in_map_inv: forall (A B: Type) (f: A -> B) (l: list A) (y: B), In y (List.map f l) -> exists x:A, y = f x /\ In x l.
Lemma list_append_map: forall (A B: Type) (f: A -> B) (l1 l2: list A), List.map f (l1 ++ l2) = List.map f l1 ++ List.map f l2.
Lemma list_append_map_inv: forall (A B: Type) (f: A -> B) (m1 m2: list B) (l: list A), List.map f l = m1 ++ m2 -> exists l1, exists l2, List.map f l1 = m1 /\ List.map f l2 = m2 /\ l = l1 ++ l2.
Lemma list_nth_z_in: forall (A: Type) (l: list A) n x, list_nth_z l n = Some x -> In x l.
Lemma list_nth_z_map: forall (A B: Type) (f: A -> B) (l: list A) n, list_nth_z (List.map f l) n = option_map f (list_nth_z l n).
Lemma list_nth_z_range: forall (A: Type) (l: list A) n x, list_nth_z l n = Some x -> 0 <= n < list_length_z l.
Lemma incl_cons_inv: forall (A: Type) (a: A) (b c: list A), incl (a :: b) c -> incl b c.
Lemma incl_app_inv_l: forall (A: Type) (l1 l2 m: list A), incl (l1 ++ l2) m -> incl l1 m.
Lemma incl_app_inv_r: forall (A: Type) (l1 l2 m: list A), incl (l1 ++ l2) m -> incl l2 m.
Lemma incl_same_head: forall (A: Type) (x: A) (l1 l2: list A), incl l1 l2 -> incl (x::l1) (x::l2).
Lemma list_map_exten: forall (A B: Type) (f f': A -> B) (l: list A), (forall x, In x l -> f x = f' x) -> List.map f' l = List.map f l.
Lemma list_map_compose: forall (A B C: Type) (f: A -> B) (g: B -> C) (l: list A), List.map g (List.map f l) = List.map (fun x => g(f x)) l.
Lemma list_map_identity: forall (A: Type) (l: list A), List.map (fun (x:A) => x) l = l.
Lemma list_map_nth: forall (A B: Type) (f: A -> B) (l: list A) (n: nat), nth_error (List.map f l) n = option_map f (nth_error l n).
Lemma list_length_map: forall (A B: Type) (f: A -> B) (l: list A), List.length (List.map f l) = List.length l.
Lemma list_in_map_inv: forall (A B: Type) (f: A -> B) (l: list A) (y: B), In y (List.map f l) -> exists x:A, y = f x /\ In x l.
Lemma list_append_map: forall (A B: Type) (f: A -> B) (l1 l2: list A), List.map f (l1 ++ l2) = List.map f l1 ++ List.map f l2.
Lemma list_append_map_inv: forall (A B: Type) (f: A -> B) (m1 m2: list B) (l: list A), List.map f l = m1 ++ m2 -> exists l1, exists l2, List.map f l1 = m1 /\ List.map f l2 = m2 /\ l = l1 ++ l2.