(std effect)

Reference

Overview

Tail-resumptive effect handlers: declare operations, invoke them, and install dynamic handlers.

(import (std prelude))
(import (std effect))

(defeffect Console
  (say (-> string void))
  #:default ((say (fun (s) (println s)))))

(defun (greet who) (say (str "hello " who)))

(greet "world")                          ; default handler: prints to stdout
(with-handler ((say (fun (s) (ignore s))))
  (greet "nobody"))                      ; custom handler: suppresses output

An effect operation is a dynamic parameter holding a handler function. Invoking an operation reads the parameter and calls the current handler. with-handler acts as parameterize over these operation parameters. Callers perform operations without knowledge of concrete handler implementations, allowing callers to substitute behaviors (for example, redirecting logs in tests).

Execution semantics. Handlers execute directly on the stack of the invoking code without capturing continuations. A handler can either return a value (resuming execution) or raise an exception (aborting execution). Non-local control flow like generators, backtracking, or multi-shot resumption is not supported on this backend.

Generated identifiers. For each operation op, defeffect generates two identifiers: op/op (the dynamic parameter) and op (the dispatch function). Modules that expose effect operations export both.

Function color. Operations declared with (-> ...) take synchronous fun handlers and can be performed anywhere (including inside defun). Operations declared with (-bjo-> ...) take asynchronous bjoroutine handlers and can only be invoked from within bjoroutines. Prefer synchronous (-> ...) when possible; operations needing asynchronous resources can return objects that suspend independently (such as ports).

Dependencies. This module does not import the prelude, allowing the prelude to declare effects of its own. Operation parameters use runtime primitives available in any module.

See also: defeffect, with-handler, handler-of

Reference

Functions

Macros

Functions

unhandled-effect

function ↑ Functions

(: unhandled-effect (-> string %a))
(unhandled-effect operation)

Raises Unhandled when an unconfigured operation is invoked.

operation
The name of the operation.
returns
Never returns. Always raises Bjolang.Runtime.Unhandled.
raises Unhandled
Always. The message identifies the operation.

Fallback handler for operations declared without a #:default clause.

See also: defeffect

Macros

defeffect

macro ↑ Macros

(defeffect name operation ...)
(defeffect name operation ... #:default (default ...) #:cold (cold ...) #:adopt (adopt ...))

Declares effect operations with signatures and optional default handlers.

name
The effect name (used for documentation; no runtime binding is created).
operation ...
(op arrow): operation name and signature ((-> ...) or (-bjo-> ...)).
default ...
(op handler): fallback handler when no dynamic handler is installed. Operations without defaults raise Bjolang.Runtime.Unhandled.
cold ...
Operations configured to use cold dynamic parameters instead of fast parameter slots.
adopt ...
(op fn): an interceptor function that processes values returned by the handler before they reach the caller.
(defeffect Log
  (log   (-> string void))
  (audit (-bjo-> string void))
  #:default ((log (fun (s) (println s))))
  #:cold (audit))

The #:default, #:cold, and #:adopt clauses are optional and order-independent. Each operation defines a parameter (op/op) and a dispatch function (op). Handlers are installed per-operation using with-handler.

Default handlers. Provide defaults when a sensible standard implementation exists. Omit defaults when unhandled operations should fail explicitly. The handler color must match the operation signature.

Cold parameters. The dynamic environment provides 31 fast parameter slots. #:cold places an operation’s parameter in cold storage to reserve fast slots for high-frequency operations.

Resource adoption. Use #:adopt when an operation creates resources (such as ports) that require registration in the caller’s scope. If the operation returns raw data and the caller creates the resource, #:adopt is not needed.

See also: with-handler, handler-of, unhandled-effect

with-handler

macro ↑ Macros

(with-handler ((op handler) ...) body ...)

Runs a body with dynamic handlers installed for specified effect operations.

op
The operation name declared by defeffect. At least one binding required.
handler
The handler function, matching the color of the operation.
body ...
Expressions to execute. Returns the result of the final expression.
(def buf (make-box ""))
(with-handler ((log (fun (s) (box-set! buf (str (box-ref buf) s)))))
  (run-job))

Acts as parameterize over the operation parameters. Bindings are established simultaneously and restored upon exit (normal or exceptional). Handlers run directly on the stack of the code invoking the operation; exceptions raised by handlers unwind from the invocation point, not the definition site.

Fiber lifetimes. with-handler does not await background fibers spawned inside its body. Spawned fibers inherit currently installed handlers at spawn time, but may outlive the with-handler block itself. To collect results from background fibers, place accumulators outside the fiber management scope.

Forwarding to existing handlers. A handler runs with itself active. Invoking its own operation directly causes infinite recursion. Use handler-of to obtain the previously installed handler before defining the replacement.

Identifier resolution. with-handler constructs the parameter identifier directly from the operation name (log becomes op/log). If an operation is imported with a prefix or alias, use parameterize directly on the qualified parameter symbol.

See also: defeffect, handler-of

handler-of

macro ↑ Macros

(handler-of op)

Retrieves the currently installed handler function for an operation.

op
The operation name declared by defeffect.

Expands to (parameter-ref op/op). Use within with-handler bindings to delegate or wrap previously installed handlers.

See also: with-handler