What Are Handlers?
Interpreters that provide implementations for effects
Understanding What Are Handlers
Handlers are the runtime interpreters that give meaning to your effects.
Your program describes WHAT effects it needs. Handlers provide HOW those effects execute.
A handler intercepts effect operations and provides custom behavior—like logging to console, updating state, or handling errors.
Handlers are composable: stack multiple handlers to handle different effects, or override default behavior with custom implementations.
Code Example
import { Handler, stack } from "../typelang/mod.ts";
import { Console } from "../typelang/effects.ts";
// 1. Your program uses Console effect
const greet = (name: string) =>
seq()
.do(() => Console.op.log(`Hello, ${name}!`))
.return(() => `Greeted ${name}`);
// 2. Define a handler that interprets Console operations
const consoleHandler = (): Handler => ({
name: "Console",
handles: {
log: (instr, next, ctx) => {
const [message] = instr.args;
console.log(`[LOG] ${message}`); // Actual side effect!
return next(undefined);
},
warn: (instr, next, ctx) => {
const [message] = instr.args;
console.warn(`[WARN] ${message}`);
return next(undefined);
},
error: (instr, next, ctx) => {
const [message] = instr.args;
console.error(`[ERROR] ${message}`);
return next(undefined);
},
},
});
// 3. Run program with handler
const result = await stack(consoleHandler()).run(() => greet("Alice"));
// Prints: [LOG] Hello, Alice!
// Returns: "Greeted Alice"
Key Points
- Handlers map effect operations to concrete implementations
- Each handler has a name matching an effect type
- handles object maps operation names to handler functions
- Handler functions receive (instruction, next, ctx) for cancellation support
- stack(...handlers).run(program) executes with handler stack