この記事は ウェブクルー Advent Calendar 2025 の11日目の記事です。
昨日は @tatsuyanamikiさんの「新卒総合演習メンター記録 — 2ヶ月で完走させるための実務ログ」でした!
はじめに
株式会社ウェブクルー Advent Calendar 2025の11日目の記事を担当する中山(@wc-nakayama)と申します。
今回の題材は「カリー化」です。
カリー化を学ぶ中で下記の悩みに直面しました。
- そもそもカリー化ってなに?
- カリー化と部分適用って何が違うの?
- カリー化の使い所って?
この記事では カリー化とは何か・部分適用との違い を整理し、学んだことをまとめます。
※記事内で登場するコード例はScalaを用いて記載しています。
カリー化ってなに?
カリー化は、
複数引数の関数を、「1つの引数を受け取り次の引数を受け取る関数を返す形」に変換するプロセス
です。
言葉だけでは分かりづらいので、簡単なコード例を見てみましょう。
カリー化のコード例
//通常のコード
def add(a: Int,b: Int): Int = a + b
add(2, 5) // 7
add(2, 10) // 12
//カリー化されたコード
def addCurried(a: Int)(b: Int): Int = a + b
val addCurried2 = addCurried(2)
addCurried2(5) // 7
addCurried2(10) // 12
通常の関数では、すべての引数を一度に渡します。
一方、カリー化された関数では、引数を1つずつ段階的に渡すことができます。
例えば addCurried(2) とした場合、この時点ではまだ計算は実行されていません。ここでは引数 a に 2 を与えていますが、返り値は「b: Int を受け取り 2 + b を計算する関数」(つまり Int => Int 型の関数)です。
このように一部の引数だけを先に与えて、残りの引数をあとから渡すことができるのがカリー化の特徴であり、こうした使い方は部分適用とも呼ばれます。
そのため、あとから addCurried2(5) や addCurried2(10) のように使用することができます。
部分適用ってなに?
先ほど登場した部分適用についてご説明します。
部分適用は
関数に引数の一部だけを与えて、残りの引数を受け取る新しい関数を得る操作
です。
こちらもコード例を用いて説明します。
部分適用 コード例
def add(a: Int, b:Int): Int = a + b
val add2 = add(2,_: Int)
add2(5) //7
add2(10) //12
ここで使われている アンダースコア(_) は、「ここにまだ値が入っていない」ということを表しています。
この書き方によって、「最初の引数 a = 2 が固定されていて、残りの b だけ受け取れる新しい関数add2」を簡単に作ることができます。
こうした操作を部分適用と言います。
カリー化と部分適用の違い
カリー化と部分適用は根本的に違う部分があります。
カリー化
複数引数を取る関数を、
“1引数ずつ受け取り、次の関数を返す”
という連鎖に変換するプロセス自体
部分適用
複数の引数を取る関数の一部に引数を渡して、
新しい関数を生成する操作
上記の通り
カリー化 → 定義や構造(関数自体を変える)
部分適用 → 使い方や呼び出し方(実際に関数を使うときのテクニック)
つまり「カリー化されたものを部分適用する」は可能ですが、
部分適用できるからといってカリー化されているとは限りません。
カリー化ってなにがいいの?
カリー化には下記の様なメリットがあります。
- 再利用しやすい
- 一部だけ引数を与え、残りの引数を後で与えられるため、再利用性が高まる
- カリー化は先頭の引数から一つずつ渡す形で設計されているため、引数を渡す順序を強制しやすい
- 関数合成がしやすくなる
- 一つずつ引数を与えてチェーンのようにつなげられるので、高階関数や関数合成と相性が良い
- implicitパラメータとの相性がいい
- 明示的な引数部分と暗黙的に補完される引数部分をきれいに分離することができる
まとめ
-
カリー化とは?
- 複数引数の関数を、「1つの引数を受け取り次の引数を受け取る関数を返す形」に変換するプロセス
-
部分適用との違い
- カリー化は定義や構造の話
- 部分適用は適用時、使い方や呼び出し方の話
-
カリー化のいいところは?
- 再利用のしやすさ
- 高階関数、合成関数やimplicitパラメータとの相性がいい
明日は@wc-hida さんの投稿になります。よろしくお願いします。