The Procedural Fascicle

Chapter 4

Foundational library

Note: This chapter will be extended by a future fascicle.

Procedures

(lambda formals body)
syntax

Syntax: Formals is a formal parameter list as described below, and body is a body as described by Section 2.6.

Semantics: A lambda expression evaluates to a procedure. The environment in effect when the lambda expression is evaluated is remembered as part of the procedure. When the procedure is later called with some arguments, the environment in which the lambda expression was evaluated is extended by binding the variables in the parameter list to fresh locations, and the resulting argument values are stored in those locations. Then, the forms in the body of the lambda expression (which may contain definitions and thus represent a letrec* form, see Section 2.6) are evaluated sequentially in the extended environment. The results of the last expression in the body are returned as the results of the procedure call; the last expression in the body is in tail context.

Formals must have one of the following forms:

  • (variable1 ...): The procedure takes a fixed number of arguments; when the procedure is called, the arguments are stored in the bindings of the corresponding variables.

  • variable: The procedure takes any number of arguments; when the procedure is called, the sequence of arguments is converted into a newly allocated list, and the list is stored in the binding of the variable.

  • (variable1 ... variablen . <<variable_(n+1)>>): If a period . precedes the last variable, then the procedure takes n or more arguments, where n is the number of parameters before the period (there must be at least one). The value stored in the binding of the last variable is a newly allocated list of the arguments left over after all the other arguments have been matched up against the other parameters.

It is a syntax violation for a variable to appear more than once in formals.

Each procedure created as the result of evaluating a lambda expression receives (conceptually) a fresh location tag, distinct from the location tags of all existing procedures. Implementations may avoid creating a new procedure object when evaluating a lambda expression if they can prove before doing so that the behaviour of the resulting procedure when called would be the same (returning the same values and having the same side effects) as an existing procedure, for all arguments to that procedure. In this case, the lambda expression will evaluate to that existing procedure, which will retain the same location tag it was given when created.

(case-lambda case-lambda clause ...)
syntax

Syntax: Each case-lambda clause must be of the form

(formals body)

Formals must be as in a lambda form.

Semantics: A case-lambda expression evaluates to a procedure. This procedure, when applied, tries to match its arguments to the case-lambda clauses in order from left to right. The arguments match a clause if one of the following conditions is fulfilled:

  • Formals has the form (variable ...) and the number of arguments is the same as the number of formal parameters in formals.

  • Formals has the form (variable1 ...variablen . variablem) and the number of arguments is at least n . [Editorial note: Markup issue where <<variable_n+1>> does not render correctly ]

  • Formals has the form variable.

For the leftmost 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.

The procedure returned by case-lambda is given a location tag, under the same conditions as procedures returned by lambda.

Example:

(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 ())

Todo: R6RS provided a sample implementation in terms of lambda. I think this is a bad idea because case-lambda is really the primitive and lambda the derived form. Should we provide one anyway?

(procedure? obj)
procedure

Returns #t if obj is a procedure; otherwise, returns #f.

(procedure? car)
#t
(procedure? 'car)
#f
(procedure? (lambda (x) (* x x)))
#t
(procedure? '(lambda (x) (* x x)))
#f
(apply proc arg1 ... rest-args)
procedure

rest-args must be a list. proc should accept n arguments, where n is the number of args plus the length of the list rest-args.

The apply procedure calls proc with the elements of the list (append (list arg1 ...) rest-args) as the actual arguments. If a call to apply occurs in a tail context, the call to proc is also in a tail context.

Examples:

(apply + (list 3 4))
7
(define compose
  (lambda (f g)
    (lambda args
      (f (apply g args)))))
((compose sqrt *) 12 75)
30
(values obj ...)
procedure

Delivers all of its arguments to its continuation.

[Editorial note: Reference implementation as in the R7RS? ]

(call-with-values producer consumer)
procedure

producer must be a procedure which accepts zero arguments. consumer must be a procedure which accepts as many arguments as the number of values producer returns when applied to zero arguments.

The call-with-values procedure calls producer with no arguments and a continuation that, when passed some values, calls the consumer procedure with those values as arguments. The continuation for the call to consumer is the continuation of the call to call-with-values. It is a domain error if the consumer does not accept as many values as producer returned.

If a call to call-with-values occurs in a tail context, the call to consumer is also in a tail context.

Examples:

(call-with-values (lambda () (values 4 5))
                  (lambda (a b) b))
5
(call-with-values * -)
-1
(call-with-values
    (lambda () (values 'a 'b))
  (case-lambda
    (() 'zero)
    ((x) (list 'one x))
    (xs (cons 'more xs))))
(more a b)

Variable definition and binding forms

(define variable expression)
syntax
(define variable)
syntax
(define (procedure spec formals) body)
syntax
(define (procedure spec . formal) body)
syntax

Syntax: Variable is an identifier. Procedure spec is either an identifier or one of the following:

(procedure spec formals)

(procedure spec . formal)

Formal is a variable. Formals is one of the following:

variable ...

variable1 variable2 ... . variablen

Within the formal and formals, no variable may occur more than once, including in different procedure specs.

Semantics: Define is a definition form (see section 4.2) used to create variable bindings; it may appear anywhere other definitions may appear.

The first form of define evaluates the expression it is given, binds the identifier named by variable to a new location and assigns the value of the evaluation to that location. An assertion violation must be signalled if the expression returns zero values or more than one value. The continuation of the expression must not be returned to more than once: implementations should signal an assertion violation when they detect this has occurred.

The second form of define binds the identifier named by variable to a new location and assigns an unspecified value to that location.

The third and fourth variants of define are equivalent to a recursive transformation into a define expression of the first form. Define in these forms binds the identifier named by the innermost nested procedure spec to a procedure that may otherwise be expressed as a number of nested lambda expressions. The formal or formals on the left-hand side of the define form itself become the formals of the outermost lambda expression; those of the procedure spec nested within each subsequent level of nesting become the next most inner lambda expression formals. The innermost lambda expression contains the body from the define form.

Examples: The basic form of define may be used as follows.

(define three 3)
(define add3
  (lambda (x) (+ x three)))
(add3 3)
6
(define first car)
(first '(1 2))
1

The procedure-definition form of define may be used as follows.

(define (step u)
  (if (<= 0 u 1) 1 0))
(step -0.5)
0
(step 2/3)
1
(define ((equal?-proc x) y)
  (equal? x y))

(define three? (equal?-proc 3))
(three? 3)
#t
(three? 4)
#f
((equal-proc? 4) 4)
#t

Note: The second form of define is allowed by R6RS but the small language report did not include it. The ability to define higher-order procedures by nesting list-structured forms on the left-hand side of define is new in this fascicle, and is not in the small language report nor in any previous Scheme report. The (scheme base) library must export the same binding as [Editorial note: whatever large language library this ends up in ].

(define-values formals expression)
syntax

Syntax: Formals is as for a lambda expression.

Semantics: Define-values is a definition form used to create variable bindings from an expression whose evaluation may return multiple values.

The expression is evaluated, and the variables named by the formals are bound to the return values in the same way that the formals in a lambda expression are matched to the arguments in a procedure call. If the evaluation of the expression returns a number of values which cannot be reconciled with the formals, an assertion violation is signalled.

Examples:

(define-values (x y) (exact-integer-sqrt 17))
(list x y)
(4 1)
(let ()
  (define-values (x y) (values 1 2))
  (+ x y))
`3`
(define-values vs (floor/ 14 8))
vs
(1 6)
(define-alias identifier1 identifier2)
syntax

Define-alias is a definition form which causes identifier1 to refer to the same binding as identifier2. Uses of identifier1 will, throughout the region of the definition, be the same as uses of identifier2 in the sense of free-identifier=?, but not in the sense of bound-identifier=? (see [Editorial note: cross-reference to macrological fascicle ]). In particular, shadowing of identifier1 or identifier2 within regions nested inside the region where the define-alias has effect will locally cancel the effect of define-alias.

Identifier2 may refer to any kind of binding, including a variable, syntax keyword, or a pattern variable. Because identifier1 receives the same binding as identifier2, its binding has the same binding type as identifier2. If identifier2 is a variable or pattern variable, it is bound to the same location as identifier1. If identifier2 is a syntax keyword, use of identifier2 within the region of the definition invokes the same trtransformer on the macro use as a use of identifier1 would. It is a syntax violation if the identifier2 is not already bound.

Example:

(define foo 3)
(define-alias bar foo)
(+ foo bar)
6
(let-syntax
    ((s (syntax-rules (foo)
          ((_ foo) #t)
          ((_ _) #f))))
  (values (s foo)
          (s bar)
          (s s)))
#t #t #f
(let bindings body)
syntax
(let name bindings body)
syntax

Syntax: Bindings has the form

((variable1 init1) ...)

where each init is an expression. Any variable must not appear more than once in the variables. Name, if present, is an identifier.

Semantics: Let is a binding expression.

In the first form of, evaluation of a let expression proceeds as follows. The init expressions of the bindings are evaluated in an unspecified order in the current environment, the variables are bound to fresh locations holding the results, and the result of evaluating the body in this extended environment is returned. The body is evaluated in tail context if the let expression is in a tail context.

In the second form, commonly referred to as ‘named let’, the name is additionally bound as a variable within the evaluation of the body to a procedure whose parameters are the bound variables and whose body is body. Thus the execution of body may be repeated by invoking the procedure named by variable.

Examples:

(let ((x 2) (y 3))
  (* x y))
6
(let ((x 2) (y 3))
  (let ((x 7)
        (z (+ x y)))
    (* z x)))
35
(let loop ((numbers '(3 -2 1 6 -5))
           (nonneg '())
           (neg '()))
  (cond ((null? numbers) (list nonneg neg))
        ((>= (car numbers) 0)
         (loop (cdr numbers)
               (cons (car numbers) nonneg)
               neg))
        ((< (car numbers) 0)
         (loop (cdr numbers)
               nonneg
               (cons (car numbers) neg)))))
((6 1 3) (-5 -2))

Implementation:

(define-syntax let
  (syntax-rules ()
    ((_ ((var init) ...) body_0 body_1 ...)
     ((lambda (var ...) body_0 body_1 ...) init ...))
    ((_ name ((var init) ...) body_0 body_1 ...)
     ((rec (name var ...) body_0 body_1 ...) init ...))))
(let* bindings body)
syntax

Syntax: Bindings is as for let, except that the same variable can be named multiple times.

Semantics: The let* form is similar to let, but the inits are evaluated and bindings created sequentially from left to right, with the region of each binding including the bindings to its right as well as body. Thus the second init is evaluated in an environment in which the first binding is visible and initialized, and so on.

Example:

(let ((x 2) (y 3))
  (let* ((x 7)
         (z (+ x y)))
    (* z x)))
70
(let-values mv bindings body)
syntax

Syntax: Mv bindings has the form

((formals1 init1) ...)

where each formals is as for a define-values definition and each init is an expression. Any variable must not appear more than once in the set of all formals.

Semantics: The init expressions of the mv bindings are evaluated in an unspecified order as in let; and the variables occurring in the formals are bound to fresh locations containing the values returned by the inits, where the formals are matched to the return values in the same way that the formals in a lambda expression are matched to the arguments in a procedure call. Then, the body is evaluated in the extended environment, and the values of the last expression of body are returned. Each binding of a variable has body as its region. If the formals do not match, an assertion violation is signalled.

Examples:

(let-values (((a b) (values 1 2))
             ((c d) (values 3 4)))
  (list a b c d))
(1 2 3 4)
(let-values (((a b . c) (values 1 2 3 4)))
  (list a b c))
(1 2 (3 4))
(let ((a 'a) (b 'b) (x 'x) (y 'y))
  (let-values (((a b) (values x y))
               ((x y) (values a b)))
    (list a b x y)))
(x y a b)
(let*-values mv bindings body)
syntax

Syntax: Mv bindings is as for let-values, except that a variable which appears in one formals can appear again in a subsequent formals.

Example:

(let ((a 'a) (b 'b) (x 'x) (y 'y))
  (let*-values (((a b) (values x y))
                ((x y) (values a b)))
    (list a b x y)))
(x y x y)
(letrec bindings body)
syntax

Syntax: Bindings is as for let.

Semantics: The variables are bound to fresh locations, the inits are evaluated in the resulting environment (in some unspecified order), each variable is assigned to the result of the corresponding init, the body is evaluated in the resulting environment, and the values of the last expression in body are returned. Each binding of a variable has the entire letrec expression as its region, making it possible to define mutually recursive procedures.

It must be possible to evaluate each init without assigning or referring to the value of any variable. Implementations should signal an assertion violation if they detect that the value of a variable is accessed or assigned during the evaluation of any init (within the limitations of one particular evaluation order and order of evaluating the init expressions). In the most common uses of letrec, all the inits are lambda expressions and the restriction is satisfied automatically.

The continuation of each init should not be invoked more than once. Implementations should detect this and signal an assertion violation.

The body is evaluated in tail context if the letrec expression as a whole is in tail context.

Example:

(letrec ((even?
          (lambda (n)
            (if (zero? n)
                #t
                (odd? (- n 1)))))
         (odd?
          (lambda (n)
            (if (zero? n)
                #f
                (even? (- n 1))))))
  (even? 66))   
#t
(letrec* bindings body)
syntax

Syntax: Bindings is as for let.

Semantics: The variables are bound to fresh locations, each variable is assigned in left-to-right order to the result of evaluating the corresponding init (interleaving evaluations and assignments), the body is evaluated in the resulting environment, and the values of the last expression in body are returned. Despite the left-to-right evaluation and assignment order, each binding of a variable has the entire letrec* expression as its region, making it possible to define mutually recursive procedures.

It must be possible to evaluate each init without accessing or assigning the value of the corresponding variable or of any variable whose binding follows it in bindings. Implementations should signal an assertion violation if they detect that this restriction is violated.

Note: Letrec* differs from letrec in that the order of evaluation of init expressions is strictly defined as left-to-right, and the values of previously-bound variables may be accessed during the evaluation of init. While implementations which do not follow this report’s recommendation to signal an assertion violation upon use of previously-bound variables in letrec are conforming, programmers cannot rely on this behaviour in portable code.

The difference between letrec and letrec* is not quite analogous to the difference between let and let*, because in let* (but not in let) the same variable can be named multiple times in different binding clauses, which is not allowed in letrec nor in letrec*.

The continuation of each init should not be invoked more than once. Implementations should detect this and signal an assertion violation.

The body is evaluated in tail context if the letrec* expression as a whole is in tail context.

Examples:

(letrec* ((p
           (lambda (x)
             (+ 1 (q (- x 1)))))
          (q
           (lambda (y)
             (if (zero? y)
                 0
                 (+ 1 (p (- y 1))))))
          (x (p 5))
          (y x))
  y)
5
(define (means ton)
  (letrec*
     ((mean
        (lambda (f g)
          (f (/ (sum g ton) n))))
      (sum
        (lambda (g ton)
          (if (null? ton)
            0
            (if (number? ton)
                (g ton)
                (+ (sum g (car ton))
                   (sum g (cdr ton)))))))
      (n (sum (lambda (x) 1) ton)))
    (values (mean values values) ; arithmetic
            (mean exp log)       ; geometric
            (mean / /))))        ; harmonic

(means '(3 (1 4)))
8/3 2.289428... 36/19
(letrec-values mv bindings body)
syntax

Syntax: Mv bindings is as for let-values.

Semantics: All the variables in the formals are bound to fresh locations, the inits are evaluated in the resulting environment (in some unspecified order), and each variable of the formals is assigned to a corresponding value or list of values from the result of those formals init, the body is evaluated in the resulting environment, and the values of the last expression in body are returned.

The same restrictions on accessing or assigning the value of a variable named by the formals during the evaluation of any init expression, and on returning to the continuation of an init expression, which apply to letrec apply also to letrec-values. Implementation should signal an assertion violation if they detect that these restrictions are violated.

The body is evaluated in tail context if the letrec-values expression as a whole is in tail context.

Example:

(letrec-values
    (((even? odd?)
      (values (lambda (n)
                (or (zero? n)
                    (odd? (- n 1))))
              (lambda (n)
                (and (not (zero? n))
                     (even? (- n 1)))))))
  (even? 12))
#t
(letrec*-values mv bindings body)
syntax

Syntax: Mv bindings is as for let-values.

Semantics: All the variables in the formals are bound to fresh locations, each variable of the formals is assigned in left-to-right order to a corresponding value or list of values from the result of evaluating its formals init (interleaving evaluations and assignments), the body is evaluated in the resulting environment, and the values of the last expression in body are returned.

The same restrictions on the evaluation of any init expression referring to variable named in the corresponding formals or in any formals to the right of it, and on returning to the continuation of an init expression, which apply to letrec* apply also to letrec*-values. Implementation should signal an assertion violation if they detect that these restrictions are violated.

The body is evaluated in tail context if the letrec*-values expression as a whole is in tail context.

(rec variable expression)
syntax
(rec (variable formals) body)
syntax
(rec (variable . formal) body)
syntax

Syntax: Formal and formals are as for define.

Semantics: Rec is a form for creating self-recursive expressions and procedures.

In the first form of rec, the expression is evaluated in an environment in which the variable is bound to a location which will eventually contain the result of evaluating that expression. If evaluation of the expression results in an attempt to access or assign the value of the variable, or if the continuation of the evaluation of the expression is returned to more than once, an assertion violation should be signalled. This form of rec can be used to create self-recursive procedures or lazy data structures with delay, but not cyclical values.

The second and third forms of rec evaluate to a procedure whose environment contains a binding for the variable which refers to the procedure itself. The formals or formal give the arguments to the resulting procedure in the same way as in the left-hand side of define.

Examples:

(car (rec s (cons 1 (delay s))))
1
(car (force (cdr (rec s (cons 1 (delay s))))))
1
(car (force (cdr (force (cdr (rec s (cons 1 (delay s))))))))
1
((rec (fact n)
   (if (<= n 1) 1
       (* n (fact (- n 1))))) 5)
120

Implementation:

(define-syntax rec
  (syntax-rules ()
    ((_ (name . formals) body_0 body_1 ...)
     (letrec ((name (lambda formals
                      body_0 body_1 ...)))
       name))
    ((_ name expr)
     (letrec ((name expr))
       name))))

Note: This form is a combination of two historical forms, rec and named-lambda, which appeared in the RRRS but have not been included in any Scheme report since. Only the first form of rec in this report is compatible with the form which had the name rec in the RRRS; the other two forms correspond to named-lambda.

Assignments

(set! variable expression)
syntax

Syntax: Variable is a variable which is already bound to some value in some region enclosing the set! expression or at the top level. If variable is not bound, it is a violation of type &undefined. Implementations should report and detect this violation before evaluation begins in the same contexts in which they should detect other references to unbound variables (see 3.1).

Note: When the identifier on the left hand side of a set! expression is not a binding for a variable but for a syntax keyword, the set! expression is a macro use and its semantics are determined by the transformer associated with the syntax keyword, not by this entry.

Semantics: The expression is evaluated, and the resulting value is stored in the location to which the variable is bound. An unspecified value is returned.

Example:

(let ((x 2))
  (+ x 1)
  (set! x 4)
  (+ x 1))
5

Sequences

(begin definition or expression ...)
syntax
(begin expression1 expression2 ...)
syntax

When begin is invoked within a body, library body, or program body, it has the first form, with the effect of splicing the definition or expression forms contained therein into the surrounding context, such that any definitions have effect for the whole of the corresponding body.

Todo: Define what begin does at the REPL (whether it locally causes R6RS top-level body semantics within itself or not). Probably in the fascicle on libraries which will define eval.

Rationale: The first form of begin is commonly used in the output of macros [Editorial note: cross-reference ] which need to generate multiple definitions and splice them into the context in which they are expanded. It is also used by macros which generate multiple expressions, some of which are side-effectual, which may be used in either a definition or an expression context.

When begin is used in a context where definitions are not allowed, it has the second form, which is an ordinary expression. The expressions are evaluated sequentially from left to right, and the values of the last expression are returned. The last expression is in tail context if the begin expression as a whole is in tail context. The continuations of the all expressions except the last one accept any number of values and discard them. This expression type is used to sequence side effects such as assignments or input and output.

Note: There is an additional form of begin used in define-library declarations [Editorial note: cross-reference to bibliothecarial fascicle ].

Examples:

(let ()
  (define x 3)
  (begin
    (define y 4)
    (define z 5))
  (+ x y z))
12
(define x 1)
(+ (begin
     (set! x 2)
     (* x 3))
   4)
10
(+ (begin
     (define x 2)
     (* x 3))
   4)
syntax violation [Editorial note: allow extension which permits this? ]

Conditional and looping forms

(if test consequent alternative)
syntax
(if test consequent)
syntax

Syntax: Test, consequent, and alternative must be expressions.

Semantics: An if expression is evaluated as follows: first, test is evaluated. If it yields a true value (see [Editorial note: cross reference to booleans in the valued fascicle ]), then consequent is evaluated and its values are returned. Otherwise alternate is evaluated and its values are returned. If test yields #f and no alternate is specified, then the result of the expression is unspecified.

The consequent and alternate expressions are in tail context if the if expression itself is.

(and test1 ...)
syntax

Syntax: The tests are expressions.

Semantics: If there are no tests, #t is returned. Otherwise, the test expressions are evaluated from left to right until a test returns #f or the last test is reached. In the former case, the and expression returns #f without evaluating the remaining expressions. In the latter case, the last expression is evaluated and its values are returned.

The last test expression is in tail context if the and expression itself is.

Examples:

(and (= 2 2) (> 2 1))
#t (and (= 2 2) (< 2 1)) => #f (and 1 2 'c '(f g)) => (f g) (and) => #t

Implementation:

(define-syntax and
  (syntax-rules ()
    ((and) #t)
    ((and test) test)
    ((and test1 test2 ...)
     (if test1 (and test2 ...) #f))))
(or test1)
syntax

Syntax: The tests are expressions.

Semantics: If there are no tests, #f is returned. Otherwise, the <test> expressions are evaluated from left to right until a test returns a true value, or the last test is reached. In the former case, the or expression returns that value without evaluating the remaining expressions. In the latter case, the last expression is evaluated and its values are returned.

The last test expression is in tail context if the or expression itself is.

Examples:

(or (= 2 2) (> 2 1))
#t (or (= 2 2) (< 2 1)) => #t (or #f #f #f) => #f (or '(b c) (/ 3 0)) => (b c)

Implementation:

(define-syntax or
  (syntax-rules ()
    ((or) #f)
    ((or test) test)
    ((or test1 test2 ...)
     (let ((x test1))
       (if x x (or test2 ...))))))
(cond cond clause ...)
syntax
=>
auxiliary syntax
else
auxiliary syntax

Syntax: Each cond clause has one of the forms

(test)

(test body)

(test => expression)

(generator guard => expression)

The last cond clause may additionally have the form

(else body)

The test, generator, and guards are all expressions.

Note: The syntax of the second, third, and fourth cond clause types is not ambiguous because the auxiliary syntax keyword => is not a valid expression nor definition on its own.

Semantics: A cond expression is evaluated by checking the cond clauses in order from left to right until the condition required by one of them is satisfied; then that clause is chosen to generate the result of evaluating the cond expression, which is returned. The condition required by each cond clause, and how it generates the result, is determined by the syntax of each clause:

  • For clauses of the form (test), the condition for the clause is satisfied if the evaluating the test expression yields a true value. The result is the value that was returned by the evaluation of the test expression.

  • For clauses of the form (test body), the condition for the clause is satisfied if evaluating the test expression yields a true value. The result is generated by evaluating the body. The body is in tail context if the cond expression as a whole is in tail context.

  • For clauses of the form (test => expression), the condition for the clause is satisfied if evaluating the test expression yields a true value. The result is generated by first evaluating the expression. This evaluation must yield a procedure of one argument. This procedure is called with the result of the prior evaluation of the test expression to give the result for the clause. The procedure is called in tail context if the cond expression is in tail context.

  • For clauses of the form (generator guard => expression), the guard expression must evaluate to a procedure. The condition for the clause is satisfied if the result of calling this procedure with the values yielded by evaluating the generator expression is a true value. The result is generated by first evaluating the expression. This evaluation must yield a procedure which takes as many arguments as there were values resulting from the prior evaluation of the generator expression. This procedure is then called with those values as arguments to give the result for the clause. The procedure is called in tail context if the cond expression is in tail context.

  • If the final clause is of the form (else body), its condition is always satisfied. The result is generated by evaluating the body. The body is in tail context if the cond expression as a whole is in tail context.

If none of the clauses have their conditions satisfied, the evaluation of the cond expression returns an unspecified value.

Implementation:

(define-syntax cond
  (syntax-rules (else =>)
    ((_) (if #f #f))
    ((_ (else body_0 body_1 ...))
     (let () body_0 body_1 ...))
    ((_ (test => proc) clause ...)
     (let ((val test))
       (if val (proc val) (cond clause ...))))
    ((_ (generator guard => proc) clause ...)
     (let-values ((vals generator))
       (if (apply guard vals)
           (apply proc vals)
           (cond clause ...))))
    ((_ (test) clause ...)
     (let ((val test))
       (if val val (cond clause ...))))
    ((_ (test body_0 body_1 ...) clause ...)
     (if test (let () body_0 body_1 ...) (cond clause ...)))))

Note: The clause form (generator guard => expression) is new in this fascicle, and is not in the small language report nor in any previous version of the Scheme report. Previous versions of the Scheme report only allowed expressions, and not definitions, in cond clauses of the second form and of the else form. The (scheme base) library must export the same binding as [Editorial note: whatever large language library this ends up in ].

Issue: In previous Scheme reports, (cond) was not a syntactically valid expression. It has been made one because it may be easier to write correct macros which expand into uses of cond when zero clauses are allowed, especially if the entire cond expression is being used only for side-effects in any case. This use of cond will always return an unspecified value. A similar change has been made to case. The Working Group is especially keen to hear feedback on this change.

(when test body)
syntax
(unless test body)
syntax

Syntax: Test is an expression.

Semantics: A when or unless expression is evaluated by first evaluating the test expression. If test evaluates to a true value in a when expression, or a false value in an unless expression, the expressions are evaluated in order from left to right. The final expression is in tail context if the when or unless form itself is in tail context. Unspecified values are returned.

Implementation:

(define-syntax when
  (syntax-rules ()
    ((_ test body_0 body_1 ...)
     (if test (let () body_0 body_1 ...)))))
(define-syntax unless
  (syntax-rules ()
    ((_ test body_0 body_1 ...)
     (if (not test) (let () body_0 body_1 ...)))))

Note: Neither the R6RS nor the small language report allowed definitions inside of a when or unless, only expressions. R6RS specified that if the expressions were evaluated, the result of evaluating the when or unless expression would the result of evaluating the final expression. The small language report relaxed this to make the result of when and unless undefined in all cases, since it could not be depended on in any circumstance.

(case key case clause ...)
syntax
=>
auxiliary syntax
else
auxiliary syntax

Syntax: Key is an expression. Each case clause has one of the forms

((datum1 ...) body)

((datum1 ...) => expression)

The last case clause may additionally have the form

(else body)

Semantics: A case expression is evaluated by first evaluating the key expression to produce a single value, called the key. The case clauses are checked in order from left to right until one is found which contains a datum whose value as a literal is the same, in the sense of the eqv? procedure, as the key.

If that clause has the first form listed above, the body is evaluated and its result returned. The body is in tail context if the case expression is in tail context.

If the clause has the second form listed above, its expression is evaluated to produce a procedure of one argument. This procedure is called with a value which is eqv? to the key as its argument and the result of this procedure call is returned. The procedure is called in tail context if the case expression is in tail context.

If no other clause contains a suitable datum for the key and the last clause has the form (else body), the body is evaluated and its result returned. The body is evaluated is in tail context if the case expression is in tail context.

If no clause contains a suitable datum for the key and there is no clause beginning with the else keyword, unspecified values are returned.

Note: Because of the use of eqv? to compare the key with the datums in case clauses, only booleans, identifiers, numbers, characters, and the empty list can sensibly be used as datums in clauses, as the semantics of eqv? for these types does not depend on their location in the store, which is unspecified for literal datums of other types.

Note: Previous versions of the Scheme report only allowed expressions, and not definitions, in case clauses of the first form and of the else form.

Issue: In previous Scheme reports, (case key) was not a syntactically valid expression. It has been made one because it may be easier to write correct macros which expand into uses of case when zero clauses are allowed, especially if the entire case expression is being used only for side-effects in any case. This use of case will always return an unspecified value. A similar change has been made to cond. The Working Group is especially keen to hear feedback on this change.

(do ((variable1 init1 <<step_1>) ...) (test expression ...) command ...)
syntax

Syntax: The inits, steps, tests, and commands are expressions. The variables are distinct identifiers.

Semantics: 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 a false value, 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. The last expression is in tail context if the do expression is in tail context. If no expressions are present, then the do expression returns unspecified values.

The region of the binding of a variable 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 [Editorial note: todo: definition of tail sequences ], i.e., the last expression is also in a tail context.

Examples:

(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

Implementation: This definition of do uses a trick to expand the variable clauses.

(define-syntax do
  (syntax-rules ()
    ((_ ((var init . maybe-step) ...)
        (test expr ...)
        command ...)
     (let-syntax
         ((do-step
           (syntax-rules ()
             ((_ implicit-step) implicit-step)
             ((_ _ step) step))))
       (let loop ((var init) ...)
         (if test
             (begin
               ;; avoid an empty `begin' expression:
               (if #f #f)
               expr ...)
             (begin
               command ...
               (loop (do-step var . maybe-step) ...))))))))

Equivalence predicates

Note: Both this section, and the semantics of the procedures defined within it, will be extended by a future fascicle.

(eqv? obj1 obj2)
procedure

The eqv? procedure defines a useful equivalence relation on objects. Briefly, it returns #t if obj1 and obj2 should normally be regarded as the same object and #f otherwise. This relation is left slightly open to interpretation, but the following partial specification of eqv? must hold for all implementations.

If obj1 and obj2 are of distinct disjoint types (see [Editorial note: cross reference to the valued fascicle on types ]), eqv? always returns #f. Otherwise, eqv? behaves according to the common disjoint type of obj1 and obj2:

  • Procedure: eqv? returns #t if the two procedures have the same location tag. It may also return #t if the implementation can prove that the two procedures would behave the same for all arguments, even if they have different location tags. Otherwise, it returns #f. Note that implementations are not required to make any particular effort to prove that two procedures have equivalent behavior.

Examples:

(eqv? (lambda () 1)
      (lambda () 2))
#f
(let ((p (lambda (x) x)))
  (eqv? p p))
#t
(eqv? (lambda (x) x)
      (lambda (y) y))
unspecified
(eq? obj1 obj2)
procedure

The eq? predicate is similar to eqv? except that in some cases it is capable of discerning distinctions finer than those detectable by eqv?. It must always return #f when eqv? also would, but may return #f in some cases where eqv? would return #t.

On procedures, the eq? predicate returns #t if the procedures have the same location tag and #f otherwise.

(equal? obj1 obj2)
procedure

The equal? predicate is a coarser equivalence predicate than eqv? or eq?. Like those procedures, it returns #f if its arguments are of distinct disjoint types. Otherwise, it returns #t if and only if the (possibly infinite) unfoldings of its arguments into regular trees are the same (in the sense of equal?) as ordered trees.

On procedures, the equal? predicate behaves the same as eqv?.