Notation "[ ]" := nil (format "[ ]") : list_scope.Notation "[ x ]" := (cons x nil) : list_scope.Notation "[ x ; y ; .. ; z ]" :=  (cons x (cons y .. (cons z nil) ..))
  (format "[ '[' x ;  '/' y ;  '/' .. ;  '/' z ']' ]") : list_scope.(** Head and tail *)

  Definition hd (default:A) (l:list A) :=
    match l with
      | [] => default
      | x :: _ => x
    end.Definition hd_error (l:list A) :=
    match l with
      | [] => None
      | x :: _ => Some x
    end.Definition tl (l:list A) :=
    match l with
      | [] => []
      | _ :: l' => l'
    end.(** The [In] predicate *)
  Fixpoint In (a:A) (l:list A) : Prop :=
    match l with
      | [] => False
      | b :: l' => b = a \/ In a l'
    end.

(* Specifications: *)
Theorem nil_cons (x:A) (l:list A) : [] <> x :: l.
Theorem destruct_list (l : list A) : {x:A & {tl:list A | l = x::tl}}+{l = []}.
Lemma hd_error_tl_repr l (a:A) r : hd_error l = Some a /\ tl l = r <-> l = a :: r.
Lemma hd_error_some_nil l (a:A) : hd_error l = Some a -> l <> [].
Theorem length_zero_iff_nil (l : list A): length l = 0 <-> l = [].
Theorem hd_error_nil : hd_error (@nil A) = None.
Theorem hd_error_cons (l : list A) (x : A) : hd_error (x::l) = Some x.
Theorem app_cons_not_nil (x y:list A) (a:A) : [] <> x ++ a :: y.
Theorem app_nil_l (l:list A) : [] ++ l = l.
Theorem app_nil_r (l:list A) : l ++ [] = l.
Theorem app_nil_end_deprecated (l:list A) : l = l ++ [].
Theorem app_assoc (l m n:list A) : l ++ m ++ n = (l ++ m) ++ n.
Theorem app_assoc_reverse_deprecated (l m n:list A) : (l ++ m) ++ n = l ++ m ++ n.
Theorem app_comm_cons (x y:list A) (a:A) : a :: (x ++ y) = (a :: x) ++ y.
Theorem app_eq_nil (l l':list A) : l ++ l' = [] -> l = [] /\ l' = [].
Lemma app_eq_cons x y z (a : A): x ++ y = a :: z -> (x = [] /\ y = a :: z) \/ exists x', x = a :: x' /\ z = x' ++ y.
Theorem app_eq_unit (x y:list A) (a:A) : x ++ y = [a] -> x = [] /\ y = [a] \/ x = [a] /\ y = [].
Lemma elt_eq_unit l1 l2 (a b : A) : l1 ++ a :: l2 = [b] -> a = b /\ l1 = [] /\ l2 = [].
Theorem app_eq_app X (x1 x2 y1 y2: list X) : x1++x2 = y1++y2 -> exists l, (x1 = y1++l /\ y2 = l++x2) \/ (y1 = x1++l /\ x2 = l++y2).
Lemma app_inj_tail : forall (x y:list A) (a b:A), x ++ [a] = y ++ [b] -> x = y /\ a = b.
Lemma app_inj_tail_iff : forall (x y:list A) (a b:A), x ++ [a] = y ++ [b] <-> x = y /\ a = b.
Lemma length_nil : length (@nil A) = 0.
Lemma length_cons : forall (l : list A) a, length (a :: l) = S (length l).
Lemma length_app : forall l l' : list A, length (l++l') = length l + length l'.
Lemma last_length : forall (l : list A) a, length (l ++ [a]) = S (length l).
Lemma app_inv_head_iff: forall l l1 l2 : list A, l ++ l1 = l ++ l2 <-> l1 = l2.
Lemma app_inv_head: forall l l1 l2 : list A, l ++ l1 = l ++ l2 -> l1 = l2.
Lemma app_inv_tail: forall l l1 l2 : list A, l1 ++ l = l2 ++ l -> l1 = l2.
Lemma app_inv_tail_iff: forall l l1 l2 : list A, l1 ++ l = l2 ++ l <-> l1 = l2.
Theorem in_eq : forall (a:A) (l:list A), In a (a :: l).
Theorem in_cons : forall (a b:A) (l:list A), In b l -> In b (a :: l).
Theorem not_in_cons (x a : A) (l : list A): ~ In x (a::l) <-> x<>a /\ ~ In x l.
Theorem in_nil : forall a:A, ~ In a [].
Lemma in_app_or : forall (l m:list A) (a:A), In a (l ++ m) -> In a l \/ In a m.
Lemma in_or_app : forall (l m:list A) (a:A), In a l \/ In a m -> In a (l ++ m).
Lemma in_app_iff : forall l l' (a:A), In a (l++l') <-> In a l \/ In a l'.
Theorem in_split : forall x (l:list A), In x l -> exists l1 l2, l = l1++x::l2.
Lemma in_elt : forall (x:A) l1 l2, In x (l1 ++ x :: l2).
Lemma in_elt_inv : forall (x y : A) l1 l2, In x (l1 ++ y :: l2) -> x = y \/ In x (l1 ++ l2).
Lemma app_inj_pivot x1 x2 y1 y2 (a : A): x1 ++ a :: x2 = y1 ++ a :: y2 -> ((In a x1 /\ In a y2) \/ (In a x2 /\ In a y1)) \/ (x1 = y1 /\ x2 = y2).
Lemma in_inv : forall (a b:A) (l:list A), In b (a :: l) -> a = b \/ In b l.
Theorem in_dec : (forall x y:A, {x = y} + {x <> y}) -> forall (a:A) (l:list A), {In a l} + {~ In a l}.
Lemma length_tl l : length (@tl A l) = length l - 1.