Definition semi_group_fold {A: Type} (default: A) (f: A -> A -> A) (l: list A): A :=
match l with
| nil => default
| a :: l0 => fold_left f l0 a
end.
Section ListFun1'.
Context {A: Type}.
Context {RA: relation A}.
Context {EqRA: Equivalence RA}.
Instance proper_semi_group_fold: forall (f: A -> A -> A) (default: A) {Proper_f: Proper (equiv ==> equiv ==> equiv) f}, Proper (Forall2 equiv ==> equiv) (semi_group_fold default f).

(* Specifications: *)
Lemma semi_group_fold_app: forall {f} {Proper_f: Proper (equiv ==> equiv ==> equiv) f} (default: A) l l',
(forall x y z, f (f x y) z === f x (f y z)) ->
not_nil l ->
not_nil l' ->
semi_group_fold default f (l ++ l') === f (semi_group_fold default f l) (semi_group_fold default f l').
Lemma semi_group_fold_concat: forall {f} {Proper_f: Proper (equiv ==> equiv ==> equiv) f} (default: A) ls,
(forall x y z, f (f x y) z === f x (f y z)) ->
Forall not_nil ls ->
semi_group_fold default f (concat ls) === semi_group_fold default f (map (semi_group_fold default f) ls).
Lemma comm_semi_group_fold_perm: forall {f} {Proper_f: Proper (equiv ==> equiv ==> equiv) f} (default: A) l l',
(forall x y, f x y === f y x) ->
(forall x y z, f (f x y) z === f x (f y z)) ->
Permutation l l' ->
semi_group_fold default f l === semi_group_fold default f l'.