wiki

Effect handler

also: effect handlers, algebraic effects, effects, one-shot continuation

A construct that runs code which may perform an effect, and handles each effect by receiving it together with the continuation from the point where it was performed. OCaml 5 has them, with one-shot continuations: each can be resumed at most once.

Performing an effect is like raising an exception that carries a way back. The nearest enclosing handler for that effect gets the effect's value and a continuation, the rest of the computation up to the handler, and decides whether and how to resume it.

OCaml 5: an effect that asks the handler for an int. The handler answers 42 by resuming the continuation.

open Effect
open Effect.Deep
type _ Effect.t += Ask : int Effect.t
let run f =
match_with f ()
{ retc = (fun x -> x);
exnc = raise;
effc = fun (type a) (eff : a Effect.t) ->
match eff with
| Ask -> Some (fun (k : (a, _) continuation) -> continue k 42)
| _ -> None }
let n = run (fun () -> perform Ask + 1) (* 43 *)

Generators, async I/O and schedulers are all handlers: the code that performs Yield or Read does not know which of them it is running under. Continuations are one-shot, so resuming the same one twice raises Effect.Continuation_already_resumed; that keeps them cheap, since a continuation is the suspended stack itself rather than a copy of it.

A handler is a delimited form of CPS: the continuation it receives is exactly what a CPS transform would have passed explicitly, except that the code performing the effect is written in direct style.

see also

referenced by

further reading

  • G. Plotkin, M. Pretnar, “Handlers of algebraic effects”, ESOP (2009).
  • K. C. Sivaramakrishnan, S. Dolan, L. White, T. Kelly, S. Jaffer, A. Madhavapeddy, “Retrofitting effect handlers onto OCaml”, PLDI (2021).