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.

(* Specifications: *)
Lemma zipC' s1 s2 : zip' s1 s2 = zip' s2 s1.
Lemma zipA' s1 s2 s3 :
obind (zip' s1) (zip' s2 s3) = obind (zip'^~ s3) (zip' s1 s2).
Lemma zip_unitL' s : zip' (zip_unit' s) s = Some s.
Lemma zip_unitE' s1 s2 :
(exists s, zip' s1 s2 = Some s) <-> zip_unit' s1 = zip_unit' s2.
Lemma zip_sorted' s1 s2 :
sorted ord (map key s1) ->
forall s, zip' s1 s2 = Some s -> sorted ord (map key s).