Expressions and Evaluation Order

Evaluation order is observable and fixed: operator first, operands left to right, then arity checking and procedure entry.

When this matters

Evaluation order matters whenever expressions mutate a cell, print output, raise an error, or may be skipped. Lispex fixes the order so the same source never depends on a host language’s operand convention.

See it run

LISPEX
(define x 0)
(list (begin (set! x 1) x) (begin (set! x (+ x 1)) x))

Observed result

OUTPUT
(1 2)

Read the example

The first begin changes x from 0 to 1 and returns 1. Only then does the second operand read that new value, add one, store 2, and return it. list therefore receives 1 followed by 2.

How to reason about it

  • let initializers use the enclosing environment left to right; let* extends one binding at a time; letrec allocates all cells first.
  • Sequences evaluate left to right and discard non-final value packets.
  • and and or short-circuit left to right; only #f is false.

Choose quickly

ContextOrderWhat may be skipped
procedure calloperator, then operands left to rightnothing
beginforms left to rightnothing; only earlier values are discarded
iftest, then one selected branchthe unselected branch
and / oroperands left to rightthe remaining operands after the answer is known
letinitializers left to right in the outer scopenothing
let*bind and extend after each initializernothing

A common mistake

Lispex does not inherit an unspecified operand order from another Scheme implementation.

Current boundaries

  • Arity errors occur after already-required operator and operand evaluation.

Keep going

Bindings explains the different let scopes. Conditionals shows which forms deliberately stop early.

Bindings and scope · Conditionals