Section CombineJoin.
Variable A : Type.
Variable JA: Join A.
Variable pa_A : Perm_alg A.
Variable sa_A : Sep_alg A.
Variable ca_A : Canc_alg A.
Variable da_A : Disj_alg A.
(* We either need an explicit top witness or some kind of axiom of choice (if not here, then in sa_fun or somesuch).  It is a little ugly this way but I don't see any other way around. Aquinas *)
Variable A_top : A.
Variable A_top_full : full A_top.
Variable T1 : Type.
Variable T2 : Type.
Variable J1: Join T1.
Variable pa_T1: Perm_alg T1.
Variable sa_T1: Sep_alg T1.
Variable combjoin : T1 -> T1 -> T2 -> Prop.
Variable combjoin_eq : forall v1 v1' v2 v2',
combjoin v1 v1' v2 ->
combjoin v1 v1' v2' ->
v2 = v2'.
Variable combjoin_assoc : forall v1 v2 v3 v4 v5,
join v1 v2 v3 ->
combjoin v3 v4 v5 ->
{v' : T1 & join v2 v4 v' /\ combjoin v1 v' v5}.
Variable combjoin_com : forall v1 v2 v3,
combjoin v1 v2 v3 ->
combjoin v2 v1 v3.
Variable combjoin_canc : forall v1 v1' v2 v3,
combjoin v1 v2 v3 ->
combjoin v1' v2 v3 ->
v1 = v1'.
(* 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.
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.

Lemma combineJ_eq: forall x y z z' : combiner,
join x y z -> join x y z' -> z = z'.