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

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

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

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

📌 このページのポイント
CPS:答えを、続きの処理へ渡す通常:呼び出し元が答えを受け取る呼び出し元f(x)関数 freturn y計算した値 y を戻すCPS:続きを引数にして渡す呼び出し元f(x, k)関数 fk(y)継続 k:値 y を受け取って、次の処理へ継続を渡すことと、非同期の実行は別
値を呼び出し元へ返す形と、受け取った継続kへ渡す形の比較。
ひよこ ひよこ
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"は「次にすること」の意。関数が完了後に何をするかを引数で渡すスタイルだよ。

参考資料

← 用語集にもどる