Search code examples
frpbacon.js

Sequential conditions in Bacon/FRP


Is there a way to combine two streams S1 and S2 into a third S3 which emits on the first S2 event AFTER S1 has emitted?

For example:

S1 --*----------------*------*--*--*-----------
S2 ------*--*--*----------*-----------*--*--*--
S3 ------*----------------*-----------*--------

Right now I'm doing it like this, but it's probably not very efficient and doesn't capture the semantics:

S1.sampledBy(S2).skipDuplicates()

Solution

  • Assuming you want S3 to output some function of the values of S1 and S2, here is one way:

    s3 = s1.flatMapLatest(function(s1Val) {
        return s2.take(1).map(function(s2Val) {
            return someFunc(s1Val, s2Val);
        });
    });
    

    That's a general solution, but there are two simplifications:

    If you just want S1's values in S3:

    s3 = s1.flatMapLatest(function (s1Val) {
        return s2.take(1).map(s1Val);
    });
    

    If you just want S2's values:

    s3 = s1.flatMapLatest(s2.take(1));
    

    Example

    Here's a copy-paste sample test run from a javascript console, slightly cleaned up to ignore the return values from methods:

    s1 = new Bacon.Bus();
    s2 = new Bacon.Bus();
    someFunc = function(a, b) { return a + b };
    s3 = s1.flatMapLatest(function(s1Val) {
        return s2.take(1).map(function(s2Val) {
            return someFunc(s1Val, s2Val);
        });
    });
    s3.log();
    s1.push(1);
    s2.push(1);
    > VM5993 Bacon-from-git.js:1103 2
    s2.push(2);
    s2.push(3);
    s1.push(2);
    s1.push(3);
    s2.push(7);
    > VM5993 Bacon-from-git.js:1103 10