status: final (2005-08-12)
keywords: Binding, Multiple-Value Returns
See also SRFI 8: receive: Binding to multiple values, SRFI 11: Syntax for receiving multiple values, and SRFI 210: Procedures and Syntax for Multiple Values.library name: let
This SRFI is a proposal for extending
let, let*, and letrec for
receiving multiple values. The syntactic extension is fully compatible
with the existing syntax. It is the intention that single-value bindings,
i.e. (let ((var expr)) ...), and multiple-value binding can
be mixed freely and conveniently.
The most simple form of the new syntax is best explained by an example:
(define (quo-rem x y)
(values (quotient x y) (remainder x y)))
(define (quo x y)
(let ((q r (quo-rem x y)))
q))
The procedure quo-rem delivers two
values to its continuation. These values are received as q
and r in the let-expression of the procedure
quo. In other words, the syntax of let is
extended such that several variables can be specified---and these
variables receive the values delivered by the expression (quo-rem x
y).
The syntax of let is further
extended to cases in which a rest argument receives the list of all
residual values. Again by example,
(let (((values y1 y2 . y3+) (foo x))) body)In this example,
values is a
syntactic keyword indicating the presence of multiple values to be received,
and y1, y2, and y3+, resp., are
variables bound to the first value, the second value, and the list of the
remaining values, resp., as produced by (foo x). The syntactic
keyword values allows receiving all values as in (let
(((values . xs) (foo x))) body). It also allows receiving no values at
all as in (let (((values) (for-each foo list))) body).A common application of binding multiple values
is decomposing data structures into their components. This mechanism is
illustrated in its most primitive form as follows: The procedure
uncons (defined below) decomposes a pair x into
its car and its cdr and delivers them as two values to its continuation.
Then an extended let can receive these values:
(let ((car-x cdr-x (uncons x))) (foo car-x cdr-x))
Of course, for pairs this method is probably
neither faster nor clearer than using the procedures car and
cdr. However, for data structures doing substantial work
upon decomposition this is different: Extracting the element of highest
priority from a priority queue, while at the same time constructing the
residual queue, can both be more efficient and more convenient than doing
both operations independently. In fact, the quo-rem example
illustrates this point already as both quotient and remainder are
probably computed by a common exact division algorithm. (And often
caching is used to avoid executing this algorithm twice as often as
needed.)
As the last feature of this SRFI, a mechanism
is specified to store multiple values in heap-allocated data structures.
For this purpose, values->list and
values->vector construct a list (a vector, resp.) storing
all values delivered by evaluating their argument expression. Note that
these operations cannot be procedures.