Racket programmers prefer to write programs with as few side-effects
as possible, since purely functional code is more easily tested and
composed into larger programs. Interaction with the external
environment, however, requires sequencing, such as when writing to a
display, opening a graphical window, or manipulating a file on disk.
4.8.1 Effects Before: begin
Sequencing: begin, begin0, and begin-for-syntax in Reference: Racket also documents begin.
A begin expression sequences expressions:
The exprs are evaluated in order, and the result of all but
the last expr is ignored. The result from the last
expr is the result of the begin form, and it is in
tail position with respect to the begin form.
| > (print-triangle 4)|
Many forms, such as lambda or cond support a
sequence of expressions even without a begin. Such positions are
sometimes said to have an implicit begin.
| > (print-triangle 4)|
The begin form is special at the top level, at module level,
or as a body after only internal definitions. In those
positions, instead of forming an expression, the content of
begin is spliced into the surrounding context.
This splicing behavior is mainly useful for macros, as we discuss
later in Macros.
4.8.2 Effects After: begin0
Sequencing: begin, begin0, and begin-for-syntax in Reference: Racket also documents begin0.
A begin0 expression has the same syntax as a begin
The difference is that begin0 returns the result of the first
expr, instead of the result of the last expr. The
begin0 form is useful for implementing side-effects that
happen after a computation, especially in the case where the
computation produces an unknown number of results.
| > (log-times (lambda () (sleep 0.1) 0))|
| > (log-times (lambda () (values 1 2)))|
4.8.3 Effects If...: when and unless
Guarded Evaluation: when and unless in Reference: Racket also documents when and unless.
The when form combines an if-style conditional with
sequencing for the “then” clause and no “else” clause:
|(when test-expr then-expr ...)|
If test-expr produces a true value, then all of the
then-exprs are evaluated. Otherwise, no then-exprs
are evaluated. The result is #<void> in any case.
The unless form is similar:
|(unless test-expr then-expr ...)|
The difference is that the test-expr result is inverted: the
then-exprs are evaluated only if the test-expr
result is #f.
| > (enumerate '("Larry" "Curly" "Moe"))|
Larry, Curly, and Moe.