Handlers are the way in which the behaviour of effect operations is defined. This allows effectful functions to be called from a context that does not allow their effect by discharging their effect through a handler.
Handlers are defined using handle expressions:
handle {
<body>
} with {
<operation>(<typed-args>) -> <return-type> {
<handler-body>
}
...
}
This evaluates <body>
, running the given handler whenever <operation>
is called.
There is a simplified form of handle expressions for when the body is a single expression:
handle <expr> {
<operation>(<typed-args>) -> <return-type> {
<handler-body>
}
...
}
In the simplest case, this handler will simply return a value (matching the return type of the operation). From the side of the effectful code, this will should be indistinguishable (operationally) from calling a normal function which returns the return value of the handler.
However, the handler can also choose not to return by using the break
keyword. When a break
is hit it stops the execution of the handled expression,
and its argument becomes the return value of the entire handle expression. If
the argument is omitted then it returns Unit
.
This is essentially how exceptions would behave in other programming languages.