Section Elt3.
Variable elt elt' elt'' : Type.
Notation oee' := (option elt * option elt')%type.
Definition combine_l (m:t elt)(m':t elt') : t oee' :=
mapi (fun k e => (Some e, find k m')) m.
Definition combine_r (m:t elt)(m':t elt') : t oee' :=
mapi (fun k e' => (find k m, Some e')) m'.
Definition fold_right_pair (A B C:Type)(f:A->B->C->C) :=
List.fold_right (fun p => f (fst p) (snd p)).
Definition combine (m:t elt)(m':t elt') : t oee' :=
let l := combine_l m m' in
let r := combine_r m m' in
fold_right_pair (add (elt:=oee')) r l.
Hint Resolve fold_right_pair_NoDup : core.
Definition at_least_left (o:option elt)(o':option elt') :=
match o with
| None => None
| _  => Some (o,o')
end.
Definition at_least_right (o:option elt)(o':option elt') :=
match o' with
| None => None
| _  => Some (o,o')
end.
Definition at_least_one (o:option elt)(o':option elt') :=
match o, o' with
| None, None => None
| _, _  => Some (o,o')
end.
Variable f : option elt -> option elt' -> option elt''.
Definition option_cons (A:Type)(k:key)(o:option A)(l:list (key*A)) :=
match o with
| Some e => (k,e)::l
| None => l
end.
Definition map2 m m' :=
let m0 : t oee' := combine m m' in
let m1 : t (option elt'') := map (fun p => f (fst p) (snd p)) m0 in
fold_right_pair (option_cons (A:=elt'')) nil m1.
Definition at_least_one_then_f (o:option elt)(o':option elt') :=
match o, o' with
| None, None => None
| _, _  => f o o'
end.

(** Specification of [map2] *)
Lemma map2_1 :
forall m (Hm:NoDupA (@eqk elt) m) m' (Hm':NoDupA (@eqk elt') m')(x:key),
In x m \/ In x m' ->
find x (map2 m m') = f (find x m) (find x m').