(************************************************************************)
(*         *      The Rocq Prover / The Rocq Development Team           *)
(*  v      *         Copyright INRIA, CNRS and contributors             *)
(* <O___,, * (see version control and CREDITS file for authors & dates) *)
(*   \VV/  **************************************************************)
(*    //   *    This file is distributed under the terms of the         *)
(*         *     GNU Lesser General Public License Version 2.1          *)
(*         *     (see LICENSE file for the text of the license)         *)
(************************************************************************)
Require Export ListDef.
Set Implicit Arguments.
(* Set Universe Polymorphism. *)
(******************************************************************)
(** * Basics: definition of polymorphic lists and some operations *)
(******************************************************************)
(** The definition of [list] is now in [Init/Datatypes], as well as the definitions of [length] and [app] *)
#[local] Open Scope bool_scope.
Open Scope list_scope.
(** Standard notations for lists. In a special module to avoid conflicts. *)
Module ListNotations.
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.
End ListNotations.
Section Lists.
Variable A : Type.
(** 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.
End Lists.
Section Facts.
Variable A : Type.
(** *** Generic facts *)

(* Specifications: *)
(** Discrimination *)
Theorem nil_cons (x:A) (l:list A) : [] <> x :: l.
(** Destruction *)
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 <> [].
(** *** Head and tail *)
Theorem hd_error_nil : hd_error (@nil A) = None.
Theorem hd_error_cons (l : list A) (x : A) : hd_error (x::l) = Some x.
(**************************)
(** *** Facts about [app] *)
(**************************)
(** Discrimination *)
Theorem app_cons_not_nil (x y:list A) (a:A) : [] <> x ++ a :: y.
(** Concat with [nil] *)
Theorem app_nil_l (l:list A) : [] ++ l = l.
Theorem app_nil_r (l:list A) : l ++ [] = l.
(* begin hide *)
(* Deprecated since 8.3 but attribute added in 8.18 *)
Theorem app_nil_end_deprecated (l:list A) : l = l ++ [].
(* begin hide *)
(* Deprecated since 8.3 but attribute added in 8.18 *)
Theorem app_assoc_reverse_deprecated (l m n:list A) : (l ++ m) ++ n = l ++ m ++ n.
(** Facts deduced from the result of a concatenation *)
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.