Section FORALL2.
Variables A B: Type.
Variable pred: A -> option B -> bool.
Definition pred_opt (x: option A) (y: option B) :=
match x with
| None => true
| Some z => pred z y
end.
Fixpoint map_forall2 (m1: map A) (m2: map B) {struct m1}: bool :=
match m1, m2 with
| Leaf, _ => true
| Node l1 o1 r1, Leaf =>
map_forall2 l1 (Leaf B) && pred_opt o1 None && map_forall2 r1 (Leaf B)
| Node l1 o1 r1, Node l2 o2 r2 =>
map_forall2 l1 l2 && pred_opt o1 o2 && map_forall2 r1 r2
end.
Fixpoint map_forall2' (m1: map A) (m2: map B) {struct m2}: bool :=
match m1, m2 with
| Leaf, _ => true
| Node l1 o1 r1, Leaf =>
map_forall2 l1 (Leaf B) && pred_opt o1 None && map_forall2 r1 (Leaf B)
| Node l1 o1 r1, Node l2 o2 r2 =>
map_forall2' l1 l2 && pred_opt o1 o2 && map_forall2' r1 r2
end.
intro m1; induction m1; intro m2; destruct m2; simpl; intuition.
rewrite IHm1_1.
rewrite IHm1_2.
auto.
Qed.
End FORALL2.
Definition map_fmap (A B:Type) (f:A->B) : map A -> map B :=
fix map_fmap (m:map A) : map B :=
match m with
| Leaf => Leaf _
| Node m1 o m2 =>
let x := match o with
| None => None
| Some x => Some (f x)
end in
Node _ (map_fmap m1) x (map_fmap m2)
end.
intros A B m f; induction m; simpl; intros;
destruct x; simpl in *; try discriminate; auto.
destruct o; simpl; auto.
discriminate.
Qed.
intros A B m f; induction m; simpl; intros;
destruct x; simpl in *; try discriminate; auto.
destruct o; simpl; auto.
discriminate.
Qed.
intros A B m f; induction m; simpl; intros;
destruct x; simpl in *; try discriminate.
apply IHm2; auto.
apply IHm1; auto.
destruct o; simpl.
congruence.
discriminate.
Qed.
intros A B m f; induction m; simpl; intros;
destruct x; simpl in *; try discriminate.
apply IHm2; auto.
apply IHm1; auto.
destruct o; simpl.
exists a; intuition.
congruence.
discriminate.
Qed.
intros A B m f; induction m; simpl; intros.
induction x; simpl in *.
rewrite IHx; auto.
rewrite IHx; auto.
auto.
destruct x; destruct o; simpl; auto.
rewrite IHm2; auto.
rewrite IHm2; auto.
rewrite IHm1; auto.
rewrite IHm1; auto.
Qed.

Lemma fmap_unset : forall A B (m:map A) (f:A->B) x,
(map_fmap A B f (unset A m x)) =
unset B (map_fmap A B f m) x.