カリー化関数の話は、理解したつもりで実装画面に戻ると急に霧が出る。
「で、結局これは仕事でどこまで必要なのか?」という問いが、いつも机の上に残るからである。
本稿では、そのモヤモヤを無理に丸めず、🧙‍♂️(博士)と🐣(学生)の対話として最後まで運ぶ。


ある博士と学生の長い対話

これは「カリー化関数って何?」という疑問から始まり、
気づけば 計算とは何か の話に迷い込んだ記録である。
途中で何度か脱線するが、それも含めて本編。

登場人物
🧙‍♂️(博士) — 理屈を語り出すと長い。比喩が急に雑になる。
🐣(学生) — 実務寄り。腹落ちしない説明には容赦なくツッコむ。


対話開始:add(2,3)add(2)(3) は同じ顔なのか

🐣(学生)「博士、カリー化関数の説明でこのコードを見たんですけど、どう見ても別物ですよね。」

function add(a, b) {
  return a + b;
}

function curriedAdd(a) {
  return function (b) {
    return a + b;
  };
}

🧙‍♂️(博士)「よい。最初の違和感として満点である。
厳密には同じ関数ではない。じゃが“同じ結果を作れる”という意味では等価である。」

add(2, 3); // 5
curriedAdd(2)(3); // 5

🐣(学生)「形は違うが、答えは同じ。つまり“同一”ではなく“等価”ということか。」

🧙‍♂️(博士)「その通り。数式で書くとこうなる。」

(a, b) → c

a → (b → c)

へ組み替えている。これがカリー化関数の芯である。


📌 注記:等価と同一は違う

  • 同一:文字どおり同じ対象であること。
  • 等価:観測した性質(ここでは入出力の振る舞い)が一致すること。
    カリー化関数の説明では、この2つが混ざると一気にわかりにくくなる。

curriedAdd(2) は途中状態か、それとも新しい関数か

🐣(学生)「では curriedAdd(2) は、計算途中の半端な値ですか。」

🧙‍♂️(博士)「半端ではない。立派な“新しい関数”である。」

const add2 = curriedAdd(2);
add2(10); // 12

実質的には次と同じ働きになる。

b => 2 + b

🐣(学生)「なるほど。『2を足すカリー化関数』を生成しているわけですね。」

🧙‍♂️(博士)「うむ。道具箱に“+2専用レンチ”が一本増える感じで捉えるとよい。」

🐣(学生)「博士、例えが急にホームセンター寄りなんですよ。」

🧙‍♂️(博士)「数学は現場に降りてこそ価値がある。たぶん。」


正体はクロージャ:関数はコードだけでは生きていない

🧙‍♂️(博士)add2 が成り立つ理由はクロージャである。a = 2 を覚えている。」

概念図にすると次の通り。

関数
 ├ コード
 └ 環境(変数)

🐣(学生)「つまり、関数は“ソースコードの断片”ではなく“コード + 状態”の組で動く。」

🧙‍♂️(博士)「その理解は強い。ここを掴めると、カリー化関数への拒否感はかなり減る。」


でも普通の関数でよくないか問題

🐣(学生)「実務なら普通にこれで十分では?」

const url = "...";
fetchUser(url, id);

fetchUser(url)(id) にする理由、正直そんなにない気がします。」

🧙‍♂️(博士)「情報システム開発では、その直感は妥当である。
カリー化関数は“できる・できない”より、“どのスタイルを選ぶか”に近い。」

🐣(学生)「救われました。使わないと負け、みたいな話じゃないんですね。」

🧙‍♂️(博士)「そういう圧は不要である。道具は目的に従わせるべきじゃ。」


実務での重要度を冷静に見る

温度感を大雑把に表にすると次になる。

分野 重要度
情報システム 低い
Web 低〜中
科学計算 低い
関数型言語 高い
計算理論 非常に高い

🐣(学生)「情報システムでは、知らないと即死する知識ではない。」

🧙‍♂️(博士)「うむ。ただし理論を知っていると、“なぜこのAPI形状にするか”を言語化しやすくなる。」


📌 補足:実務でカリー化関数が効く場面

  • 設定を先に固定し、後段の処理へ渡したいとき(部分適用)。
  • 関数合成でパイプラインを組み、データフローを見通しよくしたいとき。
  • テスト時に依存を固定した関数を作り、振る舞いを局所化したいとき。
    一方、チームの読みやすさが落ちるなら無理に採用しないほうがよい。

「すべての関数は1引数関数」の真意

🧙‍♂️(博士)「ここで有名な台詞がある。」

すべての関数は1引数関数で表せる

🐣(学生)「聞こえは強いけど、実装感覚からは距離があります。」

🧙‍♂️(博士)「それで正常である。これは“日常実装の推奨”ではなく“表現能力の証明”なのじゃ。」

f(a, b)
f(a)(b)
(a, b) → c
a → (b → c)

🧙‍♂️(博士)「この同型性が言いたいのであって、毎行カリー化関数で書けと言っているわけではない。」

🐣(学生)「その注釈、教科書の最初に太字で入れてほしいです。」


「言葉は音波」だけでは、言語は運用できない

🐣(学生)「『言葉は音波でできている』と言われても、会話が上達するわけではない。
母音・子音・文法のほうが学習には効きますよね。」

🧙‍♂️(博士)「よい比喩である。
ラムダ計算で単一引数関数を強調するのは、理解モデルというより“存在証明”に近い。」

🐣(学生)「なるほど。わかりやすさのためではなく、削ぎ落としても計算が成立することを示したい。」

🧙‍♂️(博士)「まさにそこじゃ。」


ラムダ計算の目的:計算を最小部品へ還元する

🐣(学生)「ここまでで f(a, b)f(a)(b) は等価だとわかりました。次は、その等価性をどういう土台で説明するか、という段ですね。」

🧙‍♂️(博士)「その通り。ここで言う“入る”とは、実装テクニックの話題から一段抽象化して、 『計算そのものをどう定義するか』という理論モデルの層へ移る、という意味である。 ラムダ計算は、そのための最小モデルじゃ。変数・抽象(λx.式)・適用という最小部品だけで計算を記述できるかを問う。 この位置づけを押さえると、f(a, b)f(a)(b) の言い換えは“書き方の好み”ではなく、計算の構造として説明できる。」

ラムダ計算の狙いは、

計算とは何か

を最小の記述で定義することにある。部品は3つしかない。

変数
λx.式
関数適用

そして計算は

式の書き換え

として定義される。

🐣(学生)「つまり“実行”というより“書き換え規則の適用”で捉えるわけですね。」

🧙‍♂️(博士)「うむ。CPUの姿は消え、ルールだけが残る。」


さらに奇妙な話:数も if もループも最初はない

ラムダ計算には最初から

if
ループ

があるわけではない。それでも、構成可能である。
例えば Church numeral はこう書く。

0 = λf.λx.x
1 = λf.λx.f x
2 = λf.λx.f (f x)

🐣(学生)「2が2に見えない。完全に呪文です。」

🧙‍♂️(博士)2 は『関数 f を2回適用するカリー化関数』である。
数字の見た目は消えるが、“2である振る舞い”は残る。」

🐣(学生)「意味で数字を定義する、という発想なんですね。」

🧙‍♂️(博士)「そう。見た目ではなく作用で定義する。これが理論の癖であり魅力でもある。」


📌 注記:なぜこんな回りくどい表現をするのか
目的は“日常コーディングの短縮”ではなく、
最小の道具立てでも計算能力を失わない ことを示すためである。
この視点が、計算可能性・停止性・表現力の議論へつながる。


情報理論との違い:最小化の対象が違う

🐣(学生)「ここで疑問です。最小化なら、0/1で表すほうが単純では?」

🧙‍♂️(博士)「それは情報理論の問いである。」

情報の最小単位 = bit

一方、計算理論は

計算の最小操作 = 書き換え

に注目する。つまり

情報
計算
は別問題

である。

🐣(学生)「似た“最小”でも、測っているものが違うんですね。」

🧙‍♂️(博士)「うむ。そこを混ぜると、議論はすぐ迷子になる。」


最小モデルという思想は、即効薬ではなく境界線である

🐣(学生)「正直、ここまで聞くと『仕事には遠いな』感が出てきます。」

🧙‍♂️(博士)「それも自然な反応である。
最小モデルは“理解の近道”というより、“どこまで削って成立するか”を示す境界線に近い。」

理解の道具
ではなく
境界の証明

🐣(学生)「つまり『これ以上削れない』ことの証明。」

🧙‍♂️(博士)「その通り。理論はしばしば実装より先に、地図を作る。」


哲学との類似:最小条件を問う態度

🐣(学生)「少し哲学っぽいですね。『我思う、ゆえに我あり』みたいな。」

🧙‍♂️(博士)「近い。どちらも“最小条件”を問うている。」

Cogito
→ 存在の最小条件

ラムダ計算
→ 計算の最小条件

🐣(学生)「たしかに。正しいが、それだけでプロダクトは完成しない。」

🧙‍♂️(博士)「じゃが、その正しさが後で設計の芯になることはある。」


結論

カリー化関数は、

便利テクニック

でもある。だが本質はそれだけではない。

計算を極限まで単純化したときに現れる構造

として現れる概念である。

実務での着地点は次の3点で十分である。

  • 普段は読みやすい多引数関数を使う。
  • 関数合成や部分適用が効く箇所でカリー化関数を使う。
  • 理論は“今すぐの実装手順”ではなく“長期の設計判断”の背景知識として持つ。

🐣(学生)「つまり今日のチケットを閉じる力とは別枠。でも将来の設計には効いてくる。」

🧙‍♂️(博士)「その理解が最も実務的である。
理論は即効性に乏しいが、長期戦ではじわじわ効く。漢方みたいなものじゃな。」

🐣(学生)「急に漢方で締めるんですか。」

🧙‍♂️(博士)「よいではないか。効けば正義である。」