Fixpoint combine (m1: t A) (m2: t B) {struct m1} : t C :=
    match m1 with
    | Leaf => xcombine_r m2
    | Node l1 o1 r1 =>
        match m2 with
        | Leaf => xcombine_l m1
        | Node l2 o2 r2 => Node' (combine l1 l2) (f o1 o2) (combine r1 r2)
        end
    end.

(* Specifications: *)
Theorem gcombine: forall (m1: t A) (m2: t B) (i: positive), get i (combine m1 m2) = f (get i m1) (get i m2).
Lemma xcombine_lr : forall (A B: Type) (f g : option A -> option A -> option B) (m : t A), (forall (i j : option A), f i j = g j i) -> xcombine_l f m = xcombine_r g m.
Theorem combine_commut: forall (A B: Type) (f g: option A -> option A -> option B), (forall (i j: option A), f i j = g j i) -> forall (m1 m2: t A), combine f m1 m2 = combine g m2 m1.
Theorem gcombine: forall (m1: t A) (m2: t B) (i: positive), get i (combine m1 m2) = f (get i m1) (get i m2).
Lemma xcombine_lr : forall (A B: Type) (f g : option A -> option A -> option B) (m : t A), (forall (i j : option A), f i j = g j i) -> xcombine_l f m = xcombine_r g m.
Theorem combine_commut: forall (A B: Type) (f g: option A -> option A -> option B), (forall (i j: option A), f i j = g j i) -> forall (m1 m2: t A), combine f m1 m2 = combine g m2 m1.