Javascriptの関数にはcurry(カリー化)という概念があります。
"curry"は食べ物ではなく、アメリカの数学者、ハスケル・ブルックス・カリー(Haskell Brooks Curry)の名前に由来しています。
では食べ物でないcurryとは一体何か、具体例を交えて解説してみたいと思います。

  1. curryの例
  2. curryとは?
  3. curry化で部分適用が可能になる
  4. curryっていつ使うの?
  5. lodash.jsを使用した関数のcurry化
  6. まとめ

curryの例

百聞は一見に如かずということで、まずはcurry化されたシンプルなアロー関数を見てください。
引数n,mの足し算をする関数aがcurry化されています。

const a = (n) => (m) => n + m;
const first = a(1)(2); // 3

curryとは?

curry化とは複数の引数をもつ関数を分解することです。
外側の関数から内側の関数に引数をパスしていきます。
以下の例ではn、m、lを順に最後の関数までパスしています。

const a = function(n){
    return function(m){
        return function(l){
            return n + m + l;
        }
    }
}

curry化で部分適用が可能になる

関数には完全適用と部分適用という概念があります。
完全適応とか部分適応とか初めて聞いた!という方も多いと思うので、まずはそれぞれのコードをご覧ください。

完全適用の例

const full = (n, m) => n + m;
const b = full(1); //NaN
const c = full(1,2); // 3

引数n,mをもつ関数の例ですが、完全適用では引数分を代入しないとNaNが返ってきます。

部分適用
const part = (n) => (m) => n + m;
const b = part(1); // (m) => 1 + m;
const c = b(2); // 3;
部分適用では第一引数だけ代入しても、その代入された引数を固定値とした内側の関数が返ってきます。
※外側の引数を代入なしで、内側の引数に代入することはできません。

curryっていつ使うの?

なんとなくcurry化はわかったけど、じゃあいつ使うのかについて例を上げて説明します。
ユーザーの名前(name)と出身地(hometown)のデータが格納された連想配列から、特定の出身地のユーザーだけを取り出す関数を例にしてみます。

curry化をしていない実装例

let users = [
    { name: "yuki", hometown: "Osaka" },
    { name: "taro", hometown: "Tokyo" },
    { name: "hanako", hometown: "Osaka" },
     { name: "zirou", hometown: "Nagoya" },
]
const hasElement = (hometown, users) => users.hometown === hometown;
const osaka = users.filter( x => hasElement( "Osaka" ,  x ) );
console.log(osaka);
//  [ { name: 'yuki', hometown: 'Osaka' },
//  { name: 'hanako', hometown: 'Osaka' } ]


curry化をした実装例
let users = [
    { name: "yuki", hometown: "Osaka" },
    { name: "taro", hometown: "Tokyo" },
    { name: "hanako", hometown: "Osaka" },
    { name: "zirou", hometown: "Nagoya" },
]
const hasElement = ( hometown ) => ( x ) => x.hometown === hometown;
const osaka = users.filter(hasElement( "Osaka" )); // xを省略できる。
console.log(osaka);
//  [ { name: 'yuki', hometown: 'Osaka' },
//  { name: 'hanako', hometown: 'Osaka' } ]

関数hasElementをcurry化することでuser.filterでxを省略することができます。

lodash.jsを使用した関数のcurry化

lodash.jsとは今流行りの"モダン"なJavaScriptを書くためのライブラリーです。
lodashを使用することで簡単に早くJsコードを書くことができます。
このlodash.jsにはcurry化にも使用できるものがあるのでご紹介します。

ダウンロード
npm install --save lodash
ライブラリーのダウンロードが完了したら、lodashをimportします。あとはcurry化されていない関数を_.curryで包むだけで実装できます。

lodashを用いたcurry化の実装
import _ from 'lodash'
const a = _.curry(( n,m,l ) => n + m + l);
console.log(a(1)(2)(3)); // 6

lodashを用いたcurry化は簡単に早く、お洒落(人によっては)にコードを書けるというメリットだけでなく、一度に代入する引数の数が異なっても同じ結果を得られることができます。

console.log(a(1)(2)(3)); // 6
console.log(a(1, 2)(3)); // 6
console.log(a(1)(2, 3)); // 6
console.log(a(1, 2, 3)); // 6

もしlodashを使用せずに関数をcurry化した場合、指定された引数の数の順に代入しないと指定されていない引数の数はスルーされてしまいます。

const a = (n) => (m) => (l) => n + m + l;
console.log(a(1)(2)(3)); // 6
console.log(a(1, 2)(3)); // (l) => n + m + l
console.log(a(1)(2, 3)); // (l) => n + m + l
console.log(a(1, 2, 3)); // (m) => (l) => n + m + l
console.log(a(1, 2)(3)(4)); //8 (2がスルーされる)

まとめ

関数のcurry化とは複数の引数をもつ関数をそれぞれ引数をもつ関数に分解することです。
関数をcurry化することにより、部分適用が可能になります。
curry化しないと実装できないみたいな場面に出くわすことはあまりないと思いますが、コードをよりシンプルに書きたければ使用してみても良いかもしれません。

最後に今回参考にした動画を紹介して終わります。

ここまで読んでくれてありがとうございました。
ご質問等ありましたらSNSからご連絡をお願いいたします。