JS memo

お洒落にJavaScript。

2019年4月20日19:56

Javascriptのcurry化とは?

メインビジュアル

Javascriptのcurry化とは?

Javascriptの関数にはcurry(カリー化)という概念があります。見出しでもカレーの写真を使っちゃったのでカレーライスを想像するかもしれませんが、全く関係ないです笑。アメリカの数学者、ハスケル・ブルックス・カリー(Haskell Brooks Curry)の名前に由来しています。

では食べ物でないcurryとは一体何か、実際の使い道など見てみましょう。

目次

  1. curryの例
  2. curryとは?
  3. 部分適用?
  4. curryの使用例
  5. lodash.jsを使用した関数のcurry化
  6. まとめ
  7. 参考動画

curryの例

まずはカリー化されたシンプルなアロー関数を見てください。引数n,mを持つ関数aがカリー化されています。

const a = (n) => (m) => n + m;

const first = a(1)(2); // 3

アロー関数でカリー化された関数

curryとは?

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

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

部分適用?

カリー化された関数は部分適用が可能となります。でも部分適用って何って感じですよね。

まずは全体適用をご覧ください。

完全適用

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 a = part(1); // (m) => 1 + m;
const a2 = a(2); // 3;

上記の部分適用では第一引数だけ代入すれば、その代入された引数を固定値とした内側の関数が返ってきます。

curryの使用例

ユーザーの名前(name)と出身地(hometown)のデータが格納された連想配列から特定の出身地のユーザーのみ取り出す コードを書くとします。

non-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' } ]

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

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;
//hasElement("Osaka")は(x) => x.hometown === hometown
const osaka = users.filter(hasElement("Osaka"));
console.log(osaka);
// [ { name: 'yuki', hometown: 'Osaka' },
//  { name: 'hanako', hometown: 'Osaka' } ]

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

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

ダウンロード

npm install --save lodash

ライブラリーのダウンロードが完了したら、_からlodashをインポートします。あとは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化しないと実装できないみたいな場面に出くわすことはあまりないと思いますが、コードをよりシンプルに書きたければ使用してみても良いかもしれません。
お疲れ様でした!

参考動画

今回参考にした動画です。