7106


Bacon.jsでアキュームレータ関数を複数設定し、関数の結果しだいで後続の関数をスキップすることはできるのでしょうか？

[code]

    let bus = new Bacon.Bus();
    bus.map(accume1)  // ここの処理によってはaccume2をスキップしてaccume3の処理を行いたい
       .map(accume2)
       .map(accume3);
    bus.push(1);
    
[/code]

どういう風にすればできるのか。  
また、そもそもアキュームレータで分岐をさせたいというのはBacon.js的に正しいことなのか教えてください。

よろしくお願いいたします。


CC BY-SA 3.0
2015-02-25T14:16:11.630
7088
2015-02-26T04:57:02.937
2015-02-25T14:40:35.757
3639
7737
question
javascript
Bacon.jsで後続のアキュムレータをスキップする方法について


フロー制御には、[observable.takeWhile(property)](https://github.com/baconjs/bacon.js/#observable-
takewhile) もしくは、
[observable.flatMap(f)](https://github.com/baconjs/bacon.js/#observable-
flatmap) が使えます。 `flatMap`
を使うことになると思いますが、「スキップして実行させる」というよりも、「途中で、以降に通すストリームを定義する」形になります。

[code]

    var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
    
    $("#source").text(arr.join(', '));
    
    $("#run").click(function() {
        var stream = Bacon.sequentially(250, arr);
        var acc_power = function(x) {
            return x*x;
        };
        var acc_1k = function(x) {
            return x + 1000;
        };
        $("#result").text("");
        stream
            .takeWhile( function(x){ return x <= 8; }) // この時点の x が 8 より大きければスキップ
            .map( acc_power)
            .flatMap(function(x) {
                // この時点の x で処理を分ける
                return (x > 30) ? Bacon.once(x).map(acc_1k) : x;
            })
        .onValue(function(val) {
                $("#result").append(val + ", ");
            });
    });
[/code]

[code]

    <script src="//cdnjs.cloudflare.com/ajax/libs/bacon.js/0.7.49/Bacon.min.js"></script>
    <script src="//ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
    
    <h3>Source</h3>
    <p id="source"></p>
    <hr/>
    <button id="run">Run</button><hr/>
    <h3>Result</h3>
    <p id="result"></p>
[/code]


CC BY-SA 3.0
2015-02-26T02:45:47.857
7106
2015-02-26T04:57:02.937
2015-02-26T04:57:02.937
4978
4978
7088
answer


Yamamotoさんの示すとおりflatMapを使うか、あるいはfilterでストリームを分ける方法が使えると思います。

また、Promiseのthenやcatchのような用途を想定しているのであれば、  
Bacon.Errorを使って、onErrorやmapErrorでキャッチするという方法もあります。

[code]

    var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
    
    $("#source").text(arr.join(', '));
    
    $("#run").click(function() {
        var stream = Bacon.sequentially(250, arr);
        var acc_power = function(x) {
            return x*x;
        };
        var acc_1k = function(x) {
            return x + 1000;
        };
        $("#result").text("");
        var s = stream
            .map( acc_power)
            .flatMap(function(x) {
                // 30より小さい場合はエラー
                return (x < 30) ? new Bacon.Error(x) : x;
            })
            .map(acc_1k).map(acc_1k); // エラーの場合、この処理は飛ばされる
    
        // 正常な場合
        var unsub = s.onValue(function(val) {
                $('<p>',{text:val}).appendTo("#result");
            });
    
        // エラーの場合
        var unsub_e = s.onError(function(err) {
                $('<p>',{text:err + ' is too small'}).appendTo("#result");
            });
    });
[/code]

[code]

    <script src="http://cdnjs.cloudflare.com/ajax/libs/bacon.js/0.7.49/Bacon.min.js"></script>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
    
    <h3>Source</h3>
    <p id="source"></p>
    <hr/>
    <button id="run">Run</button><hr/>
    <h3>Result</h3>
    <p id="result"></p>
[/code]


CC BY-SA 3.0
2015-02-26T03:41:44.813
7108
2015-02-26T03:41:44.813
8305
7088
answer