Authoritative source: Handlers and resumptions

Handlers and resumptions

A handler interprets one effect installation. It may resume an operation’s continuation, abort it, transform normal return values, and guarantee observable finalization.

A basic handler

handler SilentConsole : Console = {
    function readLine() = "";
    function putStrLn(text) = Unit
};

Install it with:

handle computation with SilentConsole

The handler implements every required operation exactly once. Operation types are inherited from the effect after substituting handler parameters.

Normal return transformation

handler RaiseToEither : Raise(Error) = {
    return(item) = Right(item);
    function raise(error) = Left(error)
};

return is a contextual clause name. It transforms normal completion from the computation’s result into the handler result. When omitted, it is identity.

Finalization

finally() = releaseResource()

A handler may contain at most one finally clause. It returns Unit, cannot use resume, and runs once when the dynamic installation exits by a language-observable path: success, abortive operation, exception effect, cancellation, or recoverable target failure. Forced process destruction and hardware loss cannot be guaranteed observable.

Resumption

handler FirstChoice : Choice = {
    function choose[a:Type](options:List(a)) =
        resume(head(options))
};

resume is a scoped function supplied inside a resumable operation clause. The compiler checks continuation use against the effect’s affine or multi-shot bound. It is not a global keyword.

Handlers are deep: resumed computation remains under the same handler unless a library combinator establishes another scope.

Defaults

handler StdConsole : Console = default { ... };

A default handler is deployment convenience. It does not remove Console from the declared function type and must be coherent in the target context.

Current lowering

Statically known acyclic handler scopes specialize to direct code. Recursive and mutually recursive effectful components use one handler-local worker with a flat tuple payload and explicit success/abort continuations. Both paths preserve deep scope, return transformation, and finalization.

Common mistakes

Do not omit a required operation, use resume outside its clause, or duplicate an affine continuation. return and finally clauses have different jobs; finalization must produce Unit and cannot resume.

Recap

A handler interprets one installation, transforms normal and operation exits, and may delimit a scoped continuation. Deep scope keeps resumed work under the same interpretation.

Normative details: Language Reference §13.3–13.5.