カリー化 かりーか
簡単に言うとこんな感じ!
「複数の引数をまとめて受け取る関数」を「引数を1個ずつ受け取る関数の連鎖」に変換する技術だよ!カレーの「カリー」じゃなくて、数学者のハスケル・カリーさんの名前からきてるんだ。料理で言えば「まとめて注文」を「1品ずつ注文」に変えるイメージ!
カリー化とは
カリー化(Currying)とは、複数の引数を受け取る関数を、「1つの引数を受け取って関数を返す関数」の連鎖に変換する手法です。たとえば add(1, 2) のように2つの引数を同時に渡す関数を、add(1)(2) のように1つずつ渡せる形に変えることを指します。
名前の由来は、数学者・論理学者のハスケル・カリー(Haskell Curry)です。彼はこの概念を体系化した人物として知られており、関数型プログラミング言語「Haskell」もその名を冠しています。カリー化によって関数を部分適用(引数を一部だけ渡して新しい関数を作る)できるようになり、コードの再利用性が大きく高まります。
ビジネスパーソンの感覚で言えば「ひな型づくり」に近いです。「税率8%で計算する関数」「税率10%で計算する関数」を個別に作る代わりに、「税率を受け取って計算関数を返す関数」を1つ用意しておけば、あとは税率を差し込むだけで使い回せます。コードの重複を減らし、保守性を高める実務的な技術です。
カリー化の仕組み
カリー化の前後でどう変わるか、JavaScriptを例に見てみましょう。
カリー化「前」と「後」の比較
| 項目 | 通常の関数 | カリー化後の関数 |
|---|---|---|
| 呼び出し方 | add(1, 2) | add(1)(2) |
| 引数の渡し方 | まとめて渡す | 1つずつ渡す |
| 途中で止められる? | ❌ できない | ✅ できる(部分適用) |
| 再利用しやすい? | △ | ◎ |
// ── 通常の関数 ──────────────────────────────
function add(x, y) {
return x + y;
}
add(1, 2); // 3
// ── カリー化した関数 ─────────────────────────
function curriedAdd(x) {
return function(y) {
return x + y;
};
}
curriedAdd(1)(2); // 3
// ── 部分適用の活用例 ─────────────────────────
const add10 = curriedAdd(10); // 「10を足す関数」を生成
add10(5); // 15
add10(20); // 30
[通常の関数] [カリー化後]
add(x, y) add(x)
│ │
▼ ▼
結果 fn(y)
│
▼
結果
覚え方:「1つ渡すと、次の関数が返ってくる」
🍛 カリー化 = カレーのルーを1枚ずつ溶かすイメージ 一度に全部入れるのではなく、1枚ずつ溶かして次のステップへ進む。 「1引数 → 関数 → 1引数 → 関数 → … → 結果」という流れを思い浮かべよう。
カリー化と部分適用の違い
よく混同される「部分適用(Partial Application)」との違いも押さえておきましょう。
| 用語 | 意味 | 例 |
|---|---|---|
| カリー化 | 関数を「1引数→関数」の連鎖に変換する変換操作 | f(a,b,c) → f(a)(b)(c) |
| 部分適用 | 引数の一部を先に渡して新しい関数を作る操作 | f(a,b,c) に a だけ渡して g(b,c) を作る |
カリー化は「変換の仕組み」、部分適用は「その仕組みを使った活用法」と理解すると整理しやすいです。
歴史と背景
- 1930年代 — 数学者ハスケル・カリー(Haskell Curry)とモーゼス・シェーンフィンケル(Moses Schönfinkel)が、多引数関数を1引数関数の連鎖で表現できることを数学的に示す。厳密にはシェーンフィンケルが先に発見したが、カリーの名が定着した
- 1958年 — LISPが登場し、関数を値として扱う「第一級関数」の概念がプログラミングの世界に持ち込まれる
- 1970年代 — MLやHaskellの前身となる関数型言語の研究が進み、カリー化が言語の基本機能として組み込まれ始める
- 1990年 — 関数型言語Haskellが登場。Haskellではすべての関数がデフォルトでカリー化されており、カリー化が言語設計の中心概念に
- 2000年代〜 — JavaScriptの普及とともに関数型プログラミングのスタイルが注目され、
lodash/fpやRamdaなどのライブラリがカリー化ユーティリティを提供 - 2010年代〜 — TypeScript・Scala・Kotlin・Swiftなどのモダン言語でも関数型スタイルが一般化し、カリー化はフロントエンド・バックエンド問わず広く使われる技術になる
言語ごとのカリー化の扱い方
言語によってカリー化の扱いは大きく異なります。「最初からカリー化されている言語」と「自分でカリー化を実装する言語」に分かれます。
実務でよく見るパターン(JavaScript × Ramda)
import * as R from 'ramda';
// Ramda の curry を使ったカリー化
const multiply = R.curry((x, y) => x * y);
const double = multiply(2); // 「2倍にする関数」を生成
const triple = multiply(3); // 「3倍にする関数」を生成
double(5); // 10
triple(5); // 15
// パイプラインとの組み合わせ(実務的な使い方)
const process = R.pipe(
R.filter(x => x > 0), // 正の数だけ残す
R.map(double), // 2倍にする
R.reduce(R.add, 0) // 合計する
);
process([-1, 2, 3, -4, 5]); // (2+3+5)×2 = 20
関連する規格・RFC
※ カリー化はプログラミングの数学的概念であり、特定のIETF RFC・ISO・IEEE規格は存在しないため、このセクションは省略します。