Next: stdlib records, Previous: stdlib sorting, Up: stdlib [Index]
This chapter describes the (rnrs control (6))
library, which provides
useful control structures.
?test must be an expression.
A when
expression is evaluated by evaluating the ?test expression. Only if ?test
evaluates to a true value, the remaining ?expressions are evaluated in order. A syntax use of
when
always returns zero values.
NOTE This breaks R6RS compliance. According to the standard: if ?test evaluates to a true value: the results of the last ?expression are returned as the results of the entire
when
expression; otherwise, thewhen
expression returns unspecified values.
An unless
expression is evaluated by evaluating the ?test expression. Only if
?test evaluates to #f
, the remaining ?expressions are evaluated in order. A
syntax use of unless
always returns zero values.
NOTE This breaks R6RS compliance. According to the standard: if ?test evaluates to a true value: the results of the last ?expression are returned as the results of the entire
unless
expression; otherwise, theunless
expression returns unspecified values.
The when
and unless
expressions are derived forms. They could be defined by the
following macros:
(define-syntax when (syntax-rules () ((when test result1 result2 ...) (if test (begin result1 result2 ...))))) (define-syntax unless (syntax-rules () ((unless test result1 result2 ...) (if (not test) (begin result1 result2 ...)))))
The ?inits, ?steps, ?tests, and ?commands must be expressions. The ?variables must be pairwise distinct variables.
The do
expression is an iteration construct. It specifies a set
of variables to be bound, how they are to be initialized at the start,
and how they are to be updated on each iteration.
A do
expression is evaluated as follows: The ?init
expressions are evaluated (in some unspecified order), the
?variables are bound to fresh locations, the results of the
?init expressions are stored in the bindings of the
?variables, and then the iteration phase begins.
Each iteration begins by evaluating ?test; if the result is
#f
, then the ?commands are evaluated in order for effect,
the ?step expressions are evaluated in some unspecified order, the
?variables are bound to fresh locations holding the results, and
the next iteration begins.
If ?test evaluates to a true value, the ?expressions are
evaluated from left to right and the values of the last
?expression are returned. If no ?expressions are present,
then the do
expression returns unspecified values.
The region consists of the entire do
expression except for the
?inits.
A ?step may be omitted, in which case the effect is the same as if
(?variable ?init ?variable)
had been written
instead of (?variable ?init)
.
If a do
expression appears in a tail context, the
?expressions are a ?tail sequence in the sense of report
section baselib tail call, i.e., the last ?expression is
also in a tail context.
(do ((vec (make-vector 5)) (i 0 (+ i 1))) ((= i 5) vec) (vector-set! vec i i)) ⇒ #(0 1 2 3 4) (let ((x '(1 3 5 7 9))) (do ((x x (cdr x)) (sum 0 (+ sum (car x)))) ((null? x) sum))) ⇒ 25
The following definition of do
uses a trick to expand the
variable clauses.
(define-syntax do (syntax-rules () ((do ((var init step ...) ...) (test expr ...) command ...) (letrec ((loop (lambda (var ...) (if test (begin #f ; avoid empty begin expr ...) (begin command ... (loop (do "step" var step ...) ...)))))) (loop init ...))) ((do "step" x) x) ((do "step" x y) y)))
Each ?case-lambda-clause must be of the form:
(?formals ?body)
?formals must be as in a lambda
form (baselib expressions procedures), and ?body is as described in report
section baselib bodies.
A case-lambda
expression evaluates to a procedure. This
procedure, when applied, tries to match its arguments to the
?case-lambda-clauses in order. The arguments match a clause if
one of the following conditions is fulfilled:
(?variable …)
and the
number of arguments is the same as the number of formal parameters in
?formals.
(?variable1 … ?variableN . ?variableN+1)
and the number of arguments is at least n.
?variable
.
For the first clause matched by the arguments, the variables of the
?formals are bound to fresh locations containing the argument
values in the same arrangement as with lambda
.
The last expression of a ?body in a case-lambda
expression
is in tail context.
If the arguments match none of the clauses, an exception with condition
type &assertion
is raised.
(define foo (case-lambda (() 'zero) ((x) (list 'one x)) ((x y) (list 'two x y)) ((a b c d . e) (list 'four a b c d e)) (rest (list 'rest rest)))) (foo) ⇒ zero (foo 1) ⇒ (one 1) (foo 1 2) ⇒ (two 1 2) (foo 1 2 3) ⇒ (rest (1 2 3)) (foo 1 2 3 4) ⇒ (four 1 2 3 4 ())
The case-lambda
keyword can be defined in terms of lambda
by the following macros:
(define-syntax case-lambda (syntax-rules () ((_ (fmls b1 b2 ...)) (lambda fmls b1 b2 ...)) ((_ (fmls b1 b2 ...) ...) (lambda args (let ((n (length args))) (case-lambda-help args n (fmls b1 b2 ...) ...)))))) (define-syntax case-lambda-help (syntax-rules () ((_ args n) (assertion-violation #f "unexpected number of arguments")) ((_ args n ((x ...) b1 b2 ...) more ...) (if (= n (length '(x ...))) (apply (lambda (x ...) b1 b2 ...) args) (case-lambda-help args n more ...))) ((_ args n ((x1 x2 ... . r) b1 b2 ...) more ...) (if (>= n (length '(x1 x2 ...))) (apply (lambda (x1 x2 ... . r) b1 b2 ...) args) (case-lambda-help args n more ...))) ((_ args n (r b1 b2 ...) more ...) (apply (lambda r b1 b2 ...) args))))
Next: stdlib records, Previous: stdlib sorting, Up: stdlib [Index]