| name | effect-systems |
| description | Expert skill for designing and implementing algebraic effect systems including effect annotation, inference, handlers, polymorphism, and row-based effect typing. |
| allowed-tools | Read, Write, Edit, Bash, Glob, Grep |
| graph | {"domains":["domain:software-engineering"],"specializations":["specialization:programming-languages"],"skillAreas":["skill-area:language-design","skill-area:compiler-implementation"],"roles":["role:backend-engineer"]} |
Effect Systems Skill
Design and implement algebraic effect systems for tracking and handling computational effects in programming languages.
Capabilities
- Design effect annotation syntax
- Implement effect inference algorithms
- Implement effect checking and tracking
- Design effect handlers (algebraic effects)
- Handle effect polymorphism
- Implement effect rows and extensibility
- Design effect subtyping
- Generate effect-based optimizations
Usage
Invoke this skill when you need to:
- Add an effect system to a language
- Implement algebraic effects and handlers
- Track computational effects in types
- Design effect polymorphism
Inputs
| Parameter | Type | Required | Description |
|---|
| effectModel | string | Yes | Model (algebraic, monadic, capability) |
| inferenceStrategy | string | Yes | Strategy (annotated, inferred, mixed) |
| features | array | No | Features to implement |
| builtinEffects | array | No | Built-in effects to include |
Effect Model Options
{
"effectModel": "algebraic",
"effectModel": "monadic",
"effectModel": "capability"
}
Feature Options
{
"features": [
"effect-inference",
"effect-handlers",
"effect-polymorphism",
"effect-rows",
"effect-subtyping",
"effect-abstraction",
"resumption-control",
"multi-shot-continuations"
]
}
Output Structure
effect-system/
├── syntax/
│ ├── effect-annotation.grammar # Effect annotation syntax
│ ├── effect-handler.grammar # Handler syntax
│ └── effect-operation.grammar # Operation syntax
├── typing/
│ ├── effect-types.ts # Effect type definitions
│ ├── effect-inference.ts # Effect inference
│ ├── effect-checking.ts # Effect checking
│ └── effect-rows.ts # Row polymorphism
├── handlers/
│ ├── handler-impl.ts # Handler implementation
│ ├── continuation.ts # Continuation management
│ └── resumption.ts # Resumption handling
├── runtime/
│ ├── effect-runtime.ts # Runtime effect support
│ └── builtin-effects.ts # Built-in effects
└── tests/
├── inference.test.ts
├── handlers.test.ts
└── polymorphism.test.ts
Effect System Types
Algebraic Effects (Koka-style)
effect State<S> {
get(): S
put(s: S): ()
}
effect Exception<E> {
raise(e: E): Nothing
}
type EffectType = {
operations: Map<string, OperationType>;
}
interface OperationType {
name: string;
params: Type[];
result: Type;
}
interface FunctionType {
params: Type[];
result: Type;
effects: EffectRow;
}
type EffectRow =
| { type: 'empty' }
| { type: 'single'; effect: EffectType }
| { type: 'union'; effects: EffectType[] }
| { type: 'variable'; name: string }
| { type: ; : ; : };
Effect Handlers
handle expr with {
return(x) -> returnClause(x),
get() -> getClause(resume),
put(s) -> putClause(s, resume)
}
interface Handler {
effect: EffectType;
returnClause: (value: any) => any;
operationClauses: Map<string, OperationClause>;
}
interface OperationClause {
operation: string;
params: string[];
resumeName: string;
body: Expr;
}
function typeHandler(
expr: Expr,
handler: Handler,
env: TypeEnv
): { resultType: Type; remainingEffects: EffectRow } {
const exprType = inferType(expr, env);
(handler, exprType.);
resultType = (handler, exprType., env);
remainingEffects = (exprType., handler.);
{ resultType, remainingEffects };
}
Effect Inference
function inferEffects(expr: Expr, env: TypeEnv): InferResult {
switch (expr.type) {
case 'var':
return { type: lookupType(env, expr.name), effects: emptyRow() };
case 'lambda':
const bodyResult = inferEffects(expr.body, extendEnv(env, expr.param, expr.paramType));
return {
type: { type: 'function', param: expr.paramType, result: bodyResult.type, effects: bodyResult.effects },
effects: emptyRow()
};
case 'app':
const fnResult = inferEffects(expr.fn, env);
const argResult = inferEffects(expr.arg, env);
const fnType = fnResult.type as ;
{
: fnType.,
: (fnResult., argResult., fnType.)
};
:
opType = (env, expr., expr.);
argEffects = expr..( (a, env).);
{
: opType.,
: ((expr.), ...argEffects)
};
:
exprResult = (expr., env);
handlerResult = (expr., exprResult, env);
handlerResult;
}
}
Effect Polymorphism
interface EffectPolymorphicType {
effectVars: string[];
typeVars: string[];
type: Type;
}
type RowVariable = { type: 'rowVar'; name: string };
function unifyRows(row1: EffectRow, row2: EffectRow): Substitution {
if (row1.type === 'variable') {
return { [row1.name]: row2 };
}
if (row2.type === 'variable') {
return { [row2.name]: row1 };
}
if (row1.type === 'empty' && row2.type === 'empty') {
return {};
}
}
Continuation Management
interface Continuation<A, B> {
resume(value: A): B;
}
interface MultiShotContinuation<A, B> extends Continuation<A, B> {
clone(): MultiShotContinuation<A, B>;
}
interface OneShotContinuation<A, B> extends Continuation<A, B> {
readonly consumed: boolean;
}
class ContinuationCapture {
capture<A, B>(
prompt: Prompt,
body: (k: Continuation<A, B>) => B
): B {
const k = captureDelimited(prompt);
return body(k);
}
}
Built-in Effects
const builtinEffects = {
IO: {
operations: {
print: { params: [StringType], result: UnitType },
readLine: { params: [], result: StringType },
readFile: { params: [StringType], result: StringType },
writeFile: { params: [StringType, StringType], result: UnitType }
}
},
State: {
typeParams: ['S'],
operations: {
get: { params: [], result: TypeVar('S') },
put: { params: [TypeVar('S')], result: UnitType }
}
},
Exception: {
typeParams: ['E'],
operations: {
raise: { params: [TypeVar('E')], result: NothingType }
}
},
Async: {
operations: {
await: { : [(())], : () },
: { : [([], (), )], : (()) }
}
},
: {
: {
: { : [], : },
: { : [], : }
}
}
};
Effect-Based Optimization
function canOptimize(fn: FunctionType): OptimizationLevel {
if (isEmptyRow(fn.effects)) {
return 'pure';
}
if (onlyReads(fn.effects)) {
return 'read-only';
}
if (isLocalState(fn.effects)) {
return 'local-state';
}
return 'effectful';
}
function eliminateDeadCode(expr: Expr): Expr {
const effects = inferEffects(expr);
if (isEmptyRow(effects) && !isUsed(expr)) {
return unit;
}
return expr;
}
Workflow
- Design effect syntax - Declarations, annotations, handlers
- Define effect types - Operations, rows, polymorphism
- Implement inference - Effect inference algorithm
- Build effect checker - Verify effect annotations
- Implement handlers - Handler evaluation/compilation
- Add continuations - Delimited continuation support
- Create builtins - Common effects (IO, State, etc.)
- Generate tests - Inference, handlers, polymorphism
Best Practices Applied
- Row polymorphism for flexible effect composition
- Clear distinction between operations and handlers
- Support both inferred and annotated effects
- Efficient continuation representation
- Effect-based optimization opportunities
- Good error messages for effect mismatches
References
Target Processes
- effect-system-design.js
- type-system-implementation.js
- concurrency-primitives.js