Expressions and Evaluation Order

Evaluation order is observable and fixed. The operator runs first, then the 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, and letrec allocates all cells first.
  • Sequences evaluate left to right and discard non-final value packets.
  • and and or short-circuit left to right, and only #f is false.

Choose quickly

ContextOrderWhat may be skipped
procedure calloperator, then operands left to rightnothing
beginforms left to rightnothing, and 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 the required operator and operand evaluation has already happened.

Keep going

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

Bindings and scope · Conditionals