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

Effects

The floor has four effectful primitives: print, read, read-file, and log. All I/O goes through a single boundary — the evaluator owns an I/O implementation, which is a terminal at the REPL and a script harness in tests and in this book’s build. Nothing else in the language touches the world.

print

(print e) writes the value of e and returns nil:

(print (cons 1 (cons 2 nil)))
;; prints: (1 2)
;=> nil

Because the result is nil, print sits in the effect slot of a sequencing let rather than in the middle of an expression — for the latter, log below returns its value.

read

(read prompt) prints the prompt, reads one line from the evaluator’s input, and parses it as a datum — a value, not an expression: no evaluation, no name resolution. End of input and blank lines read as nil. The book’s build harness supplies no input, so here it reaches end-of-input at once:

(read 'ready?)
;=> nil

Under the Purple session this primitive is the REPL: the read–eval– print loop at the top of the tower is a floor program calling read (Part IV).

read-file

(read-file 'path) reads a source file and parses it into a list of forms-as-data — again values, not expressions, one list element per top-level form. The path is a symbol, resolved relative to the process working directory (with $NARJU_LIB as a fallback root, so installed builds find their libraries from anywhere):

(car (car (read-file 'lib/prelude.naj)))
;=> 'define

The first form in the prelude is a define, and its head arrives as the symbol define — plain data. define means nothing to the floor; it is the Purple session that reads this file and decides what to do with each form. read-file is the floor’s entire filesystem: the Pink-level load, the tower boot, and the prelude all come through it.

Because the file is source, the read-time transforms from earlier chapters apply: the cadr family is desugared and quasiquote is expanded before the data reaches the program.

log

(log b v) is a stage-aware debug print: with b a plain value it prints v tagged [log] and — unlike print — returns it, so it can wrap any subexpression without changing the program’s result:

(log 0 'checkpoint)
;; prints: [log] 'checkpoint
;=> 'checkpoint

The first operand is a stage dispatch, a pattern that recurs throughout the staging forms: when b is code, the log is not performed now but residualized — emitted into the program being generated, to run when that program runs. Part II gives this pattern its proper treatment; log is worth meeting early because it is the tool for watching staged programs execute.