(「カリー化」については → https://ja.wikipedia.org/wiki/%E3%82%AB%E3%83%AA%E3%83%BC%E5%8C%96)
JSは関数型言語というわけではないので、カリー化により可読性が落ちる場合もありやりすぎは禁物ですが、もちろんうれしいときもあります。
たとえば、 配列の map
を使って
const array = [1, 2, 3, 4, 5];
const squaredArray = array.map(x => Math.pow(x, 2)); // [1, 4, 9, 16, 25]
const pow3Array = array.map(x => Math.pow(x, 3)); // [1, 8, 27, 64, 125]
const pow4Array = array.map(x => Math.pow(x, 4)); // [1, 16, 81, 256, 625]
...
のような要素ごとにn乗する処理を書くとき、
const powTo = (exponents: number) => (base: number) =>
Math.pow(base, exponents);
という Math.pow
をカリー化した関数を書いておけば、同じ処理を
const array = [1, 2, 3, 4, 5];
const squaredArray = array.map(powTo(2)); // [1, 4, 9, 16, 25]
const pow3Array = array.map(powTo(3)); // [1, 8, 27, 64, 125]
const pow4Array = array.map(powTo(4)); // [1, 16, 81, 256, 625]
...
のように簡潔に書くことができます。
array.map(powTo(2))
は array.map(x => powTo(2)(x))
と同じ意味です。(一般に x => f(x)
は f
に置き換えることができます)
カリー化の主なうれしいポイントは
- 短く書けてミスを減らせること
- 部分適用した関数を作りやすくなる(複数引数関数の一部の引数をあらかじめ適用することで同じ計算の繰り返しを省ける場合もある)
だと思います。
2019/8/30 追記
他にもカリー化するとちょっと嬉しい例があったのを思い出したので追記します。
ある数 x
が与えられたときに、それを min
以上 max
以下の範囲に収める(x
が min
より小さいならば min
に切り上げし、 x
が max
より大きいならば max
に切り下げる) clamp
という関数を作るとします。
通常の実装だと以下のようになります。
const clamp = (x: number, min: number, max: number) =>
x < min ? min : max < x ? max : x
const clamped = clamp(-10, -5, 5) // -5
この関数は呼び出し側の clamp(-10, -5, 5)
の部分だけ見てもどれが x
,min
,max
なのかは見た目では分かりません(たとえば (min, max, x)
の順番かもしれない)。
しかし、以下のカリー化した関数ならば意味もより分かりやすくなります。
const clamp = (min: number, max: number) => (x: number) =>
x < min ? min : max < x ? max : x
const clamped = clamp(-5, 5)(-10) // -5
先に clamp(-5, 5)
である数x
を受け取りそれを[-5, 5]
の範囲に収める関数を作り、それに -10
を渡しています。
この書き方ならばどれが min
と max
なのか一目瞭然です。
この例は引数の数の違いに頼っていたり特殊な例ですが、こういう使い方もあるかなと思ったので紹介しました。