(** 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.

(* Specifications: *)
Lemma list_fold_right_eq: forall l base, list_fold_right l base = match l with nil => base | x :: l' => f x (list_fold_right l' base) end.
Lemma list_fold_right_spec: forall l base, list_fold_right l base = List.fold_right f base l.
Lemma in_cns: forall (A: Type) (x y: A) (l: list A), In x (y :: l) <-> y = x \/ In x l.
Lemma in_app: forall (A: Type) (x: A) (l1 l2: list A), In x (l1 ++ l2) <-> In x l1 \/ In x l2.
Lemma list_in_insert: forall (A: Type) (x: A) (l1 l2: list A) (y: A), In x (l1 ++ l2) -> In x (l1 ++ y :: l2).
Lemma list_fold_right_eq: forall l base, list_fold_right l base = match l with nil => base | x :: l' => f x (list_fold_right l' base) end.
Lemma list_fold_right_spec: forall l base, list_fold_right l base = List.fold_right f base l.
Lemma in_cns: forall (A: Type) (x y: A) (l: list A), In x (y :: l) <-> y = x \/ In x l.
Lemma in_app: forall (A: Type) (x: A) (l1 l2: list A), In x (l1 ++ l2) <-> In x l1 \/ In x l2.
Lemma list_in_insert: forall (A: Type) (x: A) (l1 l2: list A) (y: A), In x (l1 ++ l2) -> In x (l1 ++ y :: l2).