2017-02-23 6 views
1

Ramda.jsはreduce関数を提供していますが、私はramdaを使用する方法を学習しようとしており、レデューサーは良い例だと思いました。次のコードが与えられれば、より効率的で機能的なアプローチは何でしょうか?ramdaを使用してカスタムレデューサーを実装する

(function(){ 

    // Some operators. Sum and multiplication. 
    const sum = (a, b) => a + b; 
    const mult = (a, b) => a * b; 

    // The reduce function 
    const reduce = R.curry((fn, accum, list) => { 
    const op = R.curry(fn); 
    while(list.length > 0){ 
     accum = pipe(R.head, op(accum))(list); 
     list = R.drop(1, list); 
    } 
    return accum; 
    }); 

    const reduceBySum = reduce(sum, 0); 
    const reduceByMult = reduce(mult, 1); 

    const data = [1, 2, 3, 4]; 
    const result1 = reduceBySum(data); 
    const result2 = reduceByMult(data); 

    console.log(result1); // 1 + 2 + 3 + 4 => 10 
    console.log(result2); // 1 * 2 * 3 * 4 => 24 

})(); 

REPLで実行します。この:http://ramdajs.com/repl/

+0

'const reduce = R.curry((fn、accum、list)=> list.reduce(fn、accum));'に対しては機能しない特殊なケースがありますか? – user3297291

答えて

2

私は、これは現実のアプリケーションのための学習運動とはないと仮定しています。正しい?

確かに、あなたはそのコードで得ることができるいくつかの効率があります。私がテストしていない

const reduce = curry(function _reduce(fn, acc, list) { 
    var idx = 0; 
    while (idx < list.length) { 
    acc = fn(acc, list[idx]); 
    idx += 1; 
    } 
    return acc; 
}); 

が、それは唯一の番号を使用しているので、これはおそらくあなたのバージョン益:何かのようになど、すべてのディスパッチ、変換は、剥ぎ取られRAMDAの実装のコアであり、リストの各メンバに1つずつ必要な関数呼び出しがあり、それはベアボーン反復で行われます。あなたのバージョンはcurryへの呼び出しを追加し、各繰り返しで、pipehead、そのカルト化されたop関数、pipe呼び出しの結果、およびdropの呼び出しを呼び出します。だから、これは速くなければなりません。

一方、このコードは必然的に必要なものです。もっと純粋に機能するものを使いたいのであれば、再帰的なソリューションを使う必要があります。ここでは1つのバージョンです:

const reduce = curry(function _reduce(fn, acc, list) { 
    return (list.length) ? _reduce(fn, fn(acc, head(list)), tail(list)) : acc; 
}); 

これはtailへの呼び出しに上記のすべてのパフォーマンスを犠牲にします。しかし、明らかに機能的な実装の方がはっきりしています。しかし、現代の多くのJSエンジンでは、これはスタックの深さのために大きなリストでも機能しません。

テール再帰型であるため、ES2015で指定されたテールコール最適化を利用することは可能ですが、ほとんど実装されていません。それまでは、主に学問的興味があります。それが利用可能であっても、headとその中で特にtailが呼び出されるため、上記の命令型実装よりもはるかに遅くなるでしょう。

Ramdaが生成されたAPIの2回目の試みであることを知りたい場合があります。その元の著者(免責事項:私はそれらの1つです)は、後者のバージョンの行にEwedaを最初に構築しました。その実験は、まさにこれらの理由で失敗しました。 Javascriptはこの種の再帰を扱うことはできません。

+0

うん、これはちょうど学習のエクササイズだった。あなたの広範で思いやりのある応答に感謝します。私は再帰的な方法を試してみたいですが、あなたが言ったように、再帰的な最適化はありません。それでも、コードサンプルは非常に役に立ちます。再度、感謝します! –

関連する問題