Skip to content

Evaluation

Omega is call-by-value with strict left-to-right argument evaluation. Special forms govern control flow, definition, and meta-operations. Effects are dispatched through the EffectBackend. Nondeterminism is provided by amb + require.

Special forms

Some forms are evaluated specially by the machine instead of by ordinary function-call semantics:

FormPurpose
(quote x) / 'xreturn the literal datum
(quasiquote x) / \x`quote with , and ,@ escapes
(define name expr)bind in current scope
(set! name expr)mutate an existing binding
(lambda (params...) body...)create a closure
(if cond then else)one-arm or two-arm conditional
(cond (test body) ...)multi-arm conditional
(let ((name expr) ...) body...)local bindings
(let* ...), (letrec ...)sequential / mutually-recursive bindings
(begin body...)sequence
(and ...), (or ...)short-circuit logical
(effect op args...)dispatch an effect
(handle handlers... body)install effect handlers for a dynamic extent
(amb v1 v2 ...)nondeterministic choice
(require pred)succeed iff pred; backtracks otherwise
(call/cc fn)call with current continuation
(with-profile prof body)install a Profile for the body
(with-budget budget body)install a budget

Evaluation order

In (f a b c):

  1. Evaluate f to a procedure value.
  2. Evaluate a, b, c left-to-right.
  3. If f is Native and lazyArgs lists positions, those args are NOT evaluated; the native sees the un-evaluated AST.
  4. Apply f to the argument list.

Special forms can opt out of step 2 entirely (e.g. if).

The effect protocol

lisp
(effect file.read.op "/etc/hosts")

The machine pauses, an OpCall { op, args } flows to the EffectBackend, and the backend either:

  • Returns a Resumption immediately with a value the machine resumes with, or
  • Returns asynchronously via a Promise the machine awaits, or
  • Surfaces the request through the OracleAdapter (for infer.op, agent.spawn.op, etc.).

(handle ...) installs handlers for specific ops. A handler can choose to: return a value (continuing the dynamic extent), abort to an outer handler, or invoke a continuation captured during the handler.

Conditions

core/conditions/ adds Common-Lisp-style structured conditions on top of effects. A (condition kind message ...) form raises a condition; (handler-case ...) catches by kind. Conditions are first-class ConditionVal values, so they can be carried, inspected, and composed before being signalled.

This is distinct from ErrVal (a value-level error returned by some primitives) and from Contradiction (a constraint-network outcome).

amb and require — nondeterminism

lisp
(let ((tone (amb "formal" "friendly" "apologetic")))
  (let ((reply (effect infer.op (list "Reply in " tone " tone..."))))
    (require (matches-tone? reply "apologetic"))
    reply))

amb returns one of the listed alternatives. require asserts a predicate; on failure it backtracks to the most recent amb and tries the next alternative. The implementation uses captured continuations to rewind state.

Tail calls

The machine handles tail calls without growing the kont stack. A let/begin/if in tail position calls the eventual procedure with the current outer continuation, not a fresh one — so (define (loop n) (if (zero? n) 'done (loop (- n 1)))) runs in constant stack space.

See also

Source: projects/omega-lisp/src/core/eval/machine.ts (frame types, transitions), projects/omega-lisp/src/core/eval/run.ts (driver loop), projects/omega-lisp/src/core/effects/runtimeImpl.ts (effect dispatch), projects/omega-lisp/src/core/conditions/ (raise/handle).