Curryingって何、いつ使えるのか?

公開:2021/02/03
更新:2021/02/03
2 min読了の目安(約2100字TECH技術記事

今回は、JSのクロージャ(Closure)を活用したCurryingの使用例について話したいと思います。

Curryingって何?

簡単に言うとCurryingは複数のパラメータを受ける関数(function、言語によってはメソッド)を1つのパラメータを受ける複数の関数で順次に使用する形で処理することです。
例えば、doAction("とんかつ", 5, true)の代わりにdoAction("とんかつ")(5)(true)で使うことです。

なぜ使うのか?

でも、なぜCurryingを使うのかというとCurryingが役に立つ場合があります。シンプルな例を挙げてみます。直方体の面積を求める関数を作成すると以下になります。

const volume = (a, b, c) => a * b * c

この関数をCurryingに実装すると

const volume = a => b => c => a * b * c

使う時にはvolume(10)(5)(8)のような感じで使えますが、色々な方法で再利用ができます。
例えば

const area = volume(1)

こんな感じで1を1つ目のパラメータとして渡すと、長方形の面積を求めるareaという関数として再利用できます。そしてこのareaも同じく

const doubleValue = area(2)

こうすることで、渡したNumberを2倍にして返すdoubleValueという関数として再利用できます。
例) doubleValue(10) // 1 * 2 * 10 = 20

他のCurryingを使う例を挙げてみます。Curryingを使うと今すぐ必要な情報だけもらって、関数の実際的な実行のタイミングは最後の情報が入力されるタイミングまで後回しにするのができます。コードでみると下記になります。

const server = address => loginInfo => サーバ接続情報

const connection = server("http://server-address")としたら、connectionはただserverから返してきた他の関数です。まだサーバへの接続はしていません。connection({"username": "user1", "password": "pw1234"})としたら、ようやくサーバへの接続が始まります。
つまり、ログイン情報が与えられていない状態ではまだ接続する理由がなく、サーバ接続に対する情報は事前に準備しておいても構わないので、準備していてログイン情報が与えられたら使用するのです。
もっと進むと

const server = address => loginInfo => {
  // サーバ接続後
  const loginToken = //
  return request => {
    // loginTokenを使ってサーバに特定のrequestを求めるコード
  }
}

const connection = server("server-address")
 
const request = connection({"username": "user1", "password": "pw1234"})
 
const request2 = connection({"username": "user2", "password": "1234pw"})

このように、同一connectionでrequest関数を別々に作り、それぞれのユーザのために使うことができ、新しい関数が返却された形なのでお互い干渉せずにloginTokenをもっています。それでrequest使用時にlogin情報を再び送信する必要もなく、loginTokenはそれぞれのrequestに別々な形で存在するので安全です。

つまり、Curryingを使うと最終的に求めることの実行を最後に必要な情報が与えられるまで後回しにすることで色々な方法で活用ができるということです。こちらの例もserverconnectionも持たなくrequestだけ再利用したい場合は以下のように使えます。

const request = server("server-address")({"username": "user1", "password": "pw1234"});

まとめ

Curryingを使う得られるメリットをもう一度まとめて並べると以下になります。

  • 関数のパラメータを好きなだけ持つことができる
  • 関数の実行を最後のパラメータが与えられるまで先後回しにすることができる
  • 特定の値を固定したまま関数を再利用することができる