Section Fold_More.
(** ** Additional properties of fold *)
(** When a function [f] is compatible and allows transpositions, we can compute [fold f] in any order. *)
Variables (A:Type)(eqA:A->A->Prop)(st:Equivalence eqA)(f:key->elt->A->A).
(** This is more convenient than a [compat_op eqke ...]. In fact, every [compat_op], [compat_bool], etc, should become a [Proper] someday. *)
Hypothesis Comp : Proper (E.eq==>eq==>eqA==>eqA) f.
(** As noticed by P. Casteran, asking for the general [SetoidList.transpose] here is too restrictive. Think for instance of [f] being [M.add] : in general, [M.add k e (M.add k e' m)] is not equivalent to [M.add k e' (M.add k e m)]. Fortunately, we will never encounter this situation during a real [fold], since the keys received by this [fold] are unique. Hence we can ask the transposition property to hold only for non-equal keys.  This idea could be push slightly further, by asking the transposition property to hold only for (non-equal) keys living in the map given to [fold]. Please contact us if you need such a version.  FSets could also benefit from a restricted [transpose], but for this case the gain is unclear. *)
Definition transpose_neqkey :=
forall k k' e e' a, ~E.eq k k' ->
eqA (f k e (f k' e' a)) (f k' e' (f k e a)).
Hypothesis Tra : transpose_neqkey.
Hint Resolve NoDupA_eqk_eqke NoDupA_rev elements_3w : map.

Lemma fold_add : forall m k e i, ~In k m ->
eqA (fold f (add k e m) i) (f k e (fold f m i)).