効果ハンドラ (effect handlers)

Algebraic Effects が「throw/try-catch の一般化」と言うとき、その一般化の正体がこれ — 例外・可変状態・generator・async・非決定性・コルーチンを、たった1つの「効果を perform → handler が(限定)継続を受け取って処理」という機構の特殊例にまとめること。Plotkin & Pretnar “Handlers of Algebraic Effects” (2009) が理論的出発点。

1つの機構が制御構造を飲み込む

ハンドラは「perform された地点までの限定継続 k を受け取る関数」。k を何回呼ぶかで、おなじみの制御構造が再現される。

制御構造効果としての姿handler が継続 k を
例外 (exception)raise e を perform呼ばない(脱出のみ)
可変状態 (state)get / put s を perform1回呼ぶ(状態を引数で引き回す)
generator / iteratoryield v を perform1回呼ぶ(値を集めて一時停止)
async / awaitawait p を perform1回呼ぶ(完了時に再開=スケジューラ)
非決定性 / backtrackingchoose [a,b] を perform複数回呼ぶ(各選択肢で再開)
コルーチン双方向 yield相互に resume

鍵は「継続を何回 resume するか」

効果の性質はこの一点でほぼ決まる:

→ だから「async/await や generator や例外を言語が個別に組み込む」のをやめ、効果機構1つをユーザーに開放すれば全部ライブラリで書ける、というのが Koka / OCaml 5 / Eff の設計思想。

限定継続が実装基盤

handler が受け取る k は、perform 地点から最も近い handler までを切り取った限定継続(shift/reset 相当)。つまり効果ハンドラ = 「型のついた・名前のついた限定継続」とも言える。逆に限定継続があれば効果ハンドラはライブラリ実装できる。

handle (perform Op v) with
  | Op v, k -> ...      -- k = perform の続き(限定継続)。k(result) で再開
  | return x -> ...     -- 効果を投げずに終わった場合

なぜ重要か

「効果は代数的演算、ハンドラはその解釈」という見方で、副作用を副作用を第一級・合成可能・差し替え可能にする。同じプログラムに別ハンドラを与えれば、本番=実 I/O / テスト=モック / 探索=全列挙、がコード本体を変えずに切り替わる。Monad が型に副作用を閉じ込めて flatMap のネストと「色付き関数」問題を生むのに対し、効果ハンドラは直接的なコードのまま複数効果を自由に重ねられる。

押さえどころ(カード化候補)

関連

Graph