import sodium.*;
import java.util.Optional;

public class Promise<A> {
    public Promise(Stream<A> sDeliver) {
        this.sDeliver = sDeliver.once();
        this.oValue = this.sDeliver.map(a -> Optional.of(a))
                                   .hold(Optional.empty());
    }
    private Promise(Stream<A> sDeliver, Cell<Optional<A>> oValue) {
        this.sDeliver = sDeliver;
        this.oValue = oValue;
    }
    private Stream<A> sDeliver;
    public Cell<Optional<A>> oValue;
    public final Stream<A> then() {
        return Stream.filterOptional(Operational.value(oValue))
            .merge(sDeliver).once();
    }
    public final void thenDo(Handler<A> h) {
        Transaction.runVoid(() ->
            then().listenOnce(h)
        );
    }
    public static <A,B,C> Promise<C> lift(final Lambda2<A, B, C> f,
                                          Promise<A> pa, Promise<B> pb) {
        return Transaction.run(() -> {
            class Tuple {
                Tuple(Optional<A> oa, Optional<B> ob) {
                    this.oa = oa;
                    this.ob = ob;
                }
                Optional<A> oa;
                Optional<B> ob;
            };
            Lambda1<A,Tuple> mkA = a ->
                new Tuple(Optional.of(a), Optional.empty());
            Lambda1<B,Tuple> mkB = b ->
                new Tuple(Optional.empty(), Optional.of(b));
            Lambda2<Tuple,Tuple,Tuple> combine = (l, r) -> new Tuple(
                l.oa.isPresent() ? l.oa : r.oa,
                l.ob.isPresent() ? l.ob : r.ob);
            Lambda1<Tuple,Optional<C>> result = t ->
                t.oa.isPresent() && t.ob.isPresent()
                    ? Optional.of(f.apply(t.oa.get(), t.ob.get()))
                    : Optional.empty();
            Stream<Tuple> sA = pa.sDeliver.map(a ->
                new Tuple(Optional.of(a), Optional.empty()));
            Cell<Tuple> vA = pa.oValue.map(oa ->
                new Tuple(oa, Optional.empty()));
            Stream<Tuple> sB = pb.sDeliver.map(b ->
                new Tuple(Optional.empty(), Optional.of(b)));
            Cell<Tuple> vB = pb.oValue.map(ob ->
                new Tuple(Optional.empty(), ob));
            Stream<Tuple> sAArrives = sA.snapshot(vB, combine);
            Stream<Tuple> sBArrives = sB.snapshot(vA, combine);
            Stream<Tuple> sSimultaneous = sA.merge(sB, combine);
            Stream<C> sDeliver = Stream.filterOptional(
                    sAArrives.merge(sBArrives)
                             .merge(sSimultaneous)
                             .map(result)
                ).once();
            Cell<Optional<C>> oValue = Cell.lift(
                combine, vA, vB).map(result);
            return new Promise<C>(sDeliver, oValue);
        });
    }
}

@@ -416,22 +416,27 @@
  %7D%0A    p
-rivate
+ublic final
  Stream%3C
@@ -459,16 +459,22 @@
  public 
+final 
 Cell%3COpt

Make Promise.sDeliver public.