Section LIST_FOLD.
Variables A B: Type.
Variable f: A -> B -> B.
(** This is exactly [List.fold_left] from Coq's standard library, with [f] taking arguments in a different order. *)
Fixpoint list_fold_left (accu: B) (l: list A) : B :=
match l with nil => accu | x :: l' => list_fold_left (f x accu) l' end.
(** This is exactly [List.fold_right] from Coq's standard library, except that it runs in constant stack space. *)
Definition list_fold_right (l: list A) (base: B) : B :=
list_fold_left base (List.rev' l).
Remark list_fold_left_app:
forall l1 l2 accu,
list_fold_left accu (l1 ++ l2) = list_fold_left (list_fold_left accu l1) l2.
End LIST_FOLD.
(** Properties of list membership. *)
(** [list_disjoint l1 l2] holds iff [l1] and [l2] have no elements in common. *)
Definition list_disjoint (A: Type) (l1 l2: list A) : Prop :=
forall (x y: A), In x l1 -> In y l2 -> x <> y.
Remark list_norepet_append_commut:
forall (A: Type) (a b: list A),
list_norepet (a ++ b) -> list_norepet (b ++ a).
(** [is_tail l1 l2] holds iff [l2] is of the form [l ++ l1] for some [l]. *)
Inductive is_tail (A: Type): list A -> list A -> Prop :=
| is_tail_refl:
forall c, is_tail c c
| is_tail_cons:
forall i c1 c2, is_tail c1 c2 -> is_tail c1 (i :: c2).
Hint Resolve is_tail_refl is_tail_cons is_tail_in is_tail_cons_left: coqlib.

Lemma is_tail_trans:
forall (A: Type) (l1 l2: list A),
is_tail l1 l2 -> forall (l3: list A), is_tail l2 l3 -> is_tail l1 l3.