ラムダとアンダースコアの違いは、カレーと作曲の2つの重要な場所にあります。
カレー
カリー化とは、いくつかのパラメーターを期待する関数を1つに変換することです。パラメーターに渡すパラメーターが少なくなると、残りのパラメーターを待機する新しい関数が返されます。
R.multiply(2, 10); // 20
両方のパラメーターを関数に渡しました。
var multiplyByTwo = R.multiply(2); multiplyByTwo(10); // 20
かっこいい。 基本的には2である新しいmultiplyByTwo関数を作成し、multiply()に組み込みました。 これで、multipliByTwoに任意の値を渡すことができます。 そしてそれは、ラムダではすべての機能がカレーをサポートしているからかもしれません。
プロセスは右から左に進みます。いくつかの引数をスキップすると、Ramdaは右側の引数をスキップしたと見なします。 したがって、配列と関数を受け取る関数は通常、関数を最初の引数として、配列を2番目の引数として期待します。 しかし、アンダースコアでは反対のことが当てはまります。
_.map([1,2,3], _.add(1)) // 2,3,4
に対して:
R.map(R.add(1), [1,2,3]); // 2,3,4
「最初の操作、次にデータ」アプローチと右から左へのカリー化を組み合わせることで、必要なことを設定し、それを行う関数に戻ることができます。 その後、必要なデータをこの関数に渡すことができます。 カレーは簡単で実用的です。
var addOneToAll = R.map(R.add(1)); addOneToAll([1,2,3]); // 2,3,4
より複雑な例を次に示します。 サーバーにリクエストを行い、配列を取得して各要素からコスト値を抽出するとします。 アンダースコアを使用して、これを行うことができます:
return getItems() .then(function(items){ return _.pluck(items, 'cost'); });
Ramdaを使用すると、不要な操作を削除できます。
return getItems() .then(R.pluck('cost'));
R.pluck( 'cost')を呼び出すと、配列の各要素からコストを抽出する関数を返します。 そして、それがまさに.then()に渡す必要があるものです。 しかし、完全な幸福のためには、カレーと作曲を組み合わせる必要があります。
構成
関数合成とは、関数fとgを取り、h(x)= f(g(x))のような関数hを返す操作です。 Ramdaには、このためのcompose()関数があります。 これら2つの概念を組み合わせることで、より小さなコンポーネントから機能の複雑な作業を構築できます。
var getCostWithTax = R.compose( R.multiply(1 + TAX_RATE), // R.prop('cost') // 'cost' );
オブジェクトから値を取得し、結果に1.13を掛ける関数が判明します
標準関数「compose」は、右から左に操作を実行します。 これが直感に反すると思われる場合は、R.pipe()を使用できます。R.comipe()は、左から右にのみ機能します。
var getCostWithTax = R.pipe( R.prop('cost'), // 'cost' R.multiply(1 + TAX_RATE) // );
関数R.composeおよびR.pipeは、最大10個の引数を取ることができます。
もちろん、アンダースコアはカリー化と合成もサポートしますが、アンダースコアでのカリー化は使用するには不便なので、ほとんど使用されません。 Ramdaを使用すると、これら2つの手法を簡単に組み合わせることができます。
まず、ラムダに恋をしました。 彼女のスタイルは、テストしやすい拡張可能な宣言型コードを生成します。 合成は自然に実行され、理解しやすいコードにつながります。 しかし、その後...
promiseを返す非同期関数を使用すると、事態がさらに混乱することがわかりました。
var getCostWithTaxAsync = function() { var getCostWithTax = R.pipe( R.prop('cost'), // 'cost' R.multiply(1 + TAX_RATE) // 1.13 ); return getItem() .then(getCostWithTax); }
もちろん、これはRamdaをまったく使用しないよりはましですが、次のようなものを取得したいと思います。
var getCostWithTaxAsync = R.pipe( getItem, // R.prop('cost'), // 'cost' R.multiply(1 + TAX_RATE) // 1.13 );
ただし、getItem()はpromiseを返し、R.prop()が返す関数は値を予期するため、これは機能しません。
約束の構成
Ramda開発者に連絡して、約束を自動的にアンラップするコンポジションのバージョンを提案しました。非同期関数は価値を期待する関数に関連付けることができます。 多くの議論の後、このアプローチを新しい関数の形式で実装することに同意しました:R.pCompose()およびR.pPipe()-「p」は「約束」を意味します。
R.pPipeを使用すると、必要なことを実行できます。
var getCostWithTaxAsync = R.pPipe( getItem, // R.prop('cost'), // 'cost' R.multiply(1 + TAX_RATE) // 1.13 ); // cost