(* We would really prefer this to be:
       exists top, join (projT1 j1) (projT1 j2) top /\ full top
   but, again, we run into Type/Prop problems and wind up needing
   some form of the axiom of choice somewhere or other. *)
Definition covers (j1 j2 : ijoinable A) : Prop :=
  join (projT1 j1) (projT1 j2) A_top.Inductive combiner : Type :=
  | CEmpty
  | CPart : forall (sh : ijoinable A) (v : T1), combiner
  | CFull : forall (v : T2), combiner.Inductive combiner : Type :=
  | CEmpty
  | CPart : forall (sh : ijoinable A) (v : T1), combiner
  | CFull : forall (v : T2), combiner.Inductive combiner : Type :=
  | CEmpty
  | CPart : forall (sh : ijoinable A) (v : T1), combiner
  | CFull : forall (v : T2), combiner.Inductive combiner : Type :=
  | CEmpty
  | CPart : forall (sh : ijoinable A) (v : T1), combiner
  | CFull : forall (v : T2), combiner.Instance Join_combiner : Join combiner :=
  fun c1 c2 c3 =>
  match (c1,c2,c3) with
  | (CEmpty, CEmpty, CEmpty) => True
  | (CEmpty, CPart a v, CPart a' v') => a = a' /\ v = v'
  | (CPart a v, CEmpty, CPart a' v')  => a = a' /\ v = v'
  | (CEmpty, CFull v, CFull v') => v = v'
  | (CFull v, CEmpty, CFull v') => v = v'
  | (CPart a v, CPart a' v', CPart a'' v'') => ijoin a a' a'' /\ join v v' v''
  | (CPart a v, CPart a' v', CFull v'') => combjoin v v' v'' /\ covers a a'
  | _ => False
 end.

(* Specifications: *)
Lemma combineJ_eq: forall x y z z' : combiner, join x y z -> join x y z' -> z = z'.
Lemma combineJ_assoc: forall a b c d e : combiner, join a b d -> join d c e -> {f : combiner & join b c f /\ join a f e}.
Lemma combineJ_com: forall a b c : combiner, join a b c -> join b a c.
Lemma combineJ_canc {C1: Canc_alg T1}: forall a1 a2 b c : combiner, join a1 b c -> join a2 b c -> a1=a2.
Lemma combineJ_ex_identities: forall a , {e : combiner & join e a a}.
Lemma combineJ_self' {DA: Disj_alg A}: forall a b : combiner, join a a b -> identity a.
Lemma combineJ_self {DA: Disj_alg A}: forall a b : combiner, join a a b -> a = b.