End KeyMap.
Arguments mapk {A B V} f m.
(* zipping two finite maps with equal domains and ranges *)
(* zip_p predicate is a test for when contents of the two maps *)
(* at a given key are "combinable". typically zip_p will test *)
(* that the types of contents are equal, in the case the map is *)
(* storing dynamics *)
Section Zip.
Variables (K : ordType) (V : Type) (zip_f : V -> V -> option V).
Variable (unit_f : V -> V).
Variable (comm : commutative zip_f).
Variable (assoc : forall x y z,
obind (zip_f x) (zip_f y z) = obind (zip_f^~ z) (zip_f x y)).
Variable (unitL : forall x, zip_f (unit_f x) x = Some x).
Variable (unitE : forall x y,
(exists z, zip_f x y = Some z) <-> unit_f x = unit_f y).
Fixpoint zip' (s1 s2 : seq (K * V)) :=
match s1, s2 with
[::], [::] => Some [::]
| (k1, v1)::s1', (k2, v2)::s2' =>
if k1 == k2 then
if zip_f v1 v2 is Some v then
if zip' s1' s2' is Some s' then Some ((k1, v) :: s')
else None
else None
else None
| _, _ => None
end.
Definition zip_unit' (s : seq (K * V)) := mapf' unit_f s.

Lemma zip_unitE' s1 s2 :
(exists s, zip' s1 s2 = Some s) <-> zip_unit' s1 = zip_unit' s2.