【シーピーエス、けいぞくわたしスタイル】

CPS(継続渡しスタイル) とは?

最終更新:
💡 答えと一緒に、次の担当へバトンを渡す

関数の計算結果を呼び出し元へ直接返す代わりに、引数として受け取った「続きの処理」の関数へ渡す書き方。処理をどう続けるかを、継続という形で明示する。

📌 このページのポイント
CPS:結果を「続き」に渡す 通常:x = 1 のときfunction addOne(x) { return x + 1;}2呼び出し元へCPS:続きを表す k も渡すfunction addOne(x, k) { k(x + 1);}継続 k が 2 を受け取るそこで、次の処理を続けるこの例は同期処理。非同期とは限らない
上の関数は値を返し、下の関数は引数kとして受け取った続きを呼びます。kの具体的な処理と呼び出し部分は省略しています。コールバックのすべてがCPSではなく、実行時のスタックや非同期の動作は別の話です。
ひよこ ひよこ
CPSって、何の略?
ペンギン先生 ペンギン先生
Continuation-Passing Styleで、継続渡しスタイルと呼ぶよ。継続は、計算の結果を受け取ってその後を進める処理。関数へ、その続きも引数として渡すんだ。
ひよこ ひよこ
returnとは、どう違う?
ペンギン先生 ペンギン先生
例えば通常の形では、1を足した値をreturnで返し、呼び出し元が使うよ。CPSの形なら、addOne(x, k)がk(x + 1)を呼ぶ。ここでkが、答えを受け取る継続なんだ。どちらも計算する値は同じだけれど、続け方の表現が違うね。
ひよこ ひよこ
コールバックなら、全部CPS?
ペンギン先生 ペンギン先生
コールバックは、別の処理に呼んでもらう関数を渡す仕組み。CPSではそれを、計算の続きを表すために使うよ。イベント通知などのコールバックを全部CPSと呼ぶわけではないし、深く入れ子になっているだけでも判定できないんだ。
ひよこ ひよこ
必ず、非同期になるの?
ペンギン先生 ペンギン先生
ならないよ。今のaddOneの例は、その場でkを呼ぶ同期処理として書ける。非同期処理にも使えるけれど、継続を渡すことと、別のタイミングで実行することは分けて考えよう。async/awaitの実装が必ず同じCPS変換、という意味でもないんだ。
ひよこ ひよこ
コンパイラでは、何に使う?
ペンギン先生 ペンギン先生
処理の行き先を明示する中間表現の一つとして使えるよ。通常の続きと例外時の続きを別々に渡す、といった制御も表現できる。末尾呼び出しの形にできても、実行時のスタックが自動で減るかは、変換方法や実行環境に依存するね。
ペンギン
まとめ:ざっくりこれだけ覚えればOK!
「CPS」って出てきたら「結果を返す代わりに、受け取った続きの処理へ渡す書き方」と思えばだいたいOK!
📖 おまけ:英語の意味
「CPS (Continuation-Passing Style)」 = 継続渡しスタイル
💬 "Continuation"は「次にすること」の意。関数が完了後に何をするかを引数で渡すスタイルだよ。

参考資料

← 用語集にもどる