Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Floor Reference

Every form the floor understands, in one place. Entries marked staging are covered properly in Part II; they are listed here so the reference is complete. Special forms are recognized by head symbol and arity — a special-form name applied at the wrong arity falls through to ordinary application and, since none of these names is a bound variable, fails as unbound (let is the one exception, with its own arity error). Following the reference implementation, operator names are not values: car can head a form but cannot be passed to a function.

Literals and atoms

Numbers — 42, -7

64-bit signed integers, self-evaluating. Also the boolean encoding: predicates answer 1/0 and if branches on 0/nonzero.

#t, #f

Read-time aliases for 1 and 0. Not distinct values.

nil

The empty list. Self-evaluating; terminates proper lists; not a valid if condition; tested with null?.

Symbols — x, two-words?

A bare symbol is a variable reference, resolved at parse time to an environment position — unbound names are parse errors. A quoted symbol is data. Symbol characters: alphanumerics and + - * / ? ! < > = _ # ..

Comments — ; …

Semicolon to end of line, discarded by the reader.

Binding and control

(lambda f x body)

The unary, self-naming function. f names the closure in its own body (write _ when unused); x names the argument. Application extends the closure environment with the closure itself, then the argument — recursion without a fixpoint operator. Evaluates to #<closure>.

(f a), (f a b …)

Application. Strictly unary; (f a b) is sugar for ((f a) b), associating left. Applying a non-closure is a type error; applying code residualizes (staging).

(let x e body)

Evaluate e, bind the result to x, evaluate body. One binder; nest for more. Also the sequencing idiom: (let _ effect body).

(if c t e)

Branch on a number: 0 false, anything else true. Both branches required; nil and other non-numbers are type errors. A code condition reifies both branches and residualizes the if (staging).

Data

(cons a b) / (car p) / (cdr p)

Build a pair; take its first / second component. car/cdr of a non-pair is a type error. Lists are nil-terminated cons chains, printed (1 2 3), with (1 . 2) for improper tails.

(quote d), 'd

The datum d as a value, unevaluated. Symbols inside are data, not variables.

(quasiquote d), `d, (unquote e), ,e

A quote with holes: ,e inside a template splices the value of e. ,@ is read as plain , — no splicing. In loaded files, quasiquote is expanded at read time into cons/quote source.

(cadr p) / (caddr p) / (cadddr p)

Second / third / fourth element. Surface sugar, rewritten to car/cdr chains over the whole source tree — including quoted data, so Pink source never contains them.

Predicates

(number? e) / (symbol? e) / (null? e) / (pair? e)

Kind tests, answering 1 or 0. Never an error.

(eq? a b)

Equality, answering 1 or 0. Structural on numbers, symbols, nil, pairs, and closures; by identity on cells. Different kinds are unequal. Code operands residualize the comparison (staging); a code operand against a non-scalar raises a stage error.

(code? d e)staging

1 if e’s value is staged code. d is a stage dispatch: when it is code, the test itself residualizes.

Arithmetic

(+ a b) / (- a b) / (* a b)

Addition, subtraction, multiplication on integers. Binary only; no division. Code operands residualize the operation (staging).

Staging

(lift e)staging

Reify the value of e as next-stage code: numbers and symbols become literals, pairs of code become cons nodes, closures η-expand into staged lambdas (memoized, so a recursive function lifts to one residual definition). Lifting a cell is an error.

(run b e)staging

Stage dispatch on b: non-code b compiles e — evaluates it in a fresh scope, expecting code — and immediately executes the result; code b residualizes the run.

(lift-ref name v)staging

Cross-stage persistence: embed the live value of v in residual code as a reference, not a syntactic copy. With a code first operand, residualizes.

(evalms env-list e)staging

Evaluate a code value under an explicit environment given as a list of values. The reference base.scm’s evalms, exposed as a primitive; back half of the trans/evalms pipeline the Purple boot uses to animate source-as-data.

(trans e env)staging

Translate an s-expression value into a code value, resolving names positionally against env — a list of symbols, or (name . code) pairs that splice code in place of a variable. base.scm’s trans as a primitive.

Effects

Write the value; return nil. (log is the value-returning variant.)

(read prompt)

Print the prompt, read one input line, parse it as a datum (a value — no evaluation). End of input and blank lines read as nil.

(read-file 'path)

Parse a source file into a list of forms-as-data, one element per top-level form, with read-time transforms (cadr sugar, quasiquote) applied. The floor primitive underneath load and the tower boot.

(log b v)stage-aware

With non-code b: print v tagged [log], return it. With code b: residualize the log, persisting a non-code v as a cross-stage reference.

Errors

(throw v)

Raise the value of v as an error with a first-class payload. Unwinds to the nearest catch; uncaught, aborts the top-level form.

(catch e)

Evaluate e to a tagged list: (ok value) on success, (error payload) on error. A thrown payload arrives structurally; any other error arrives as a single symbol holding its report. Written for the Purple REPL loop; deliberately minimal.

Cells

(cell-new v) / (cell-read c) / (cell-set! c v)

Allocate a mutable cell / read it / overwrite it (returning the new value). Identity semantics: copies alias, eq? compares identity, printed #<cell N>. Cells never fold under staging: lift of a cell errors, staged cell operations residualize.

No surface syntax

One expression form exists only inside generated code, with no way to write it in source: the cross-stage persisted value (the reference’s proc), produced when staged log or lift-ref embeds a live value in residual code. Residual programs are otherwise ordinary source — which is what lets run execute them and Part III print them.