Control features
This section describes various primitive procedures which
control the flow of program execution in special ways. Procedures
in this section that invoke procedure arguments always
do so in the same dynamic environment as the call of
the original procedure. The
(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
(call-with-current-continuation procedure?)
==> #t
(apply
proc arg1 ... args
)
procedure
The apply procedure calls proc with the elements of the list
(append (list arg1 ... ) args) as the actual arguments.
(apply + (list 3 4)) ==> 7
(define compose
(lambda (f g)
(lambda args
(f (apply g args)))))
((compose sqrt *) 12 75) ==> 30
(map
proc list1 list2 ...
)
procedure
It is an error if proc does not accept as many arguments as there
are lists and return a single value.
The map procedure applies proc element-wise to the elements of the lists and returns a list of the results, in order. If more than one list is given and not all lists have the same length, map terminates when the shortest list runs out. It is an error for proc to mutate any of the lists. The dynamic order in which proc is applied to the elements of the lists is unspecified. If multiple returns occur from map, the values returned by earlier returns are not mutated.
(map cadr '((a b) (d e) (g h)))
==> (b e h)
(map (lambda (n) (expt n n))
'(1 2 3 4 5))
==> (1 4 27 256 3125)
(map + '(1 2 3) '(4 5 6 7)) ==> (5 7 9)
(let ((count 0))
(map (lambda (ignored)
(set! count (+ count 1))
count)
'(a b))) ==> (1 2) or (2 1)
(string-map
proc string1 string2 ...
)
procedure
It is an error if proc does not accept as many arguments as there
are strings and return a single character.
The string-map procedure applies proc element-wise to the elements of the strings and returns a string of the results, in order. If more than one string is given and not all strings have the same length, string-map terminates when the shortest string runs out. The dynamic order in which proc is applied to the elements of the strings is unspecified. If multiple returns occur from string-map, the values returned by earlier returns are not mutated.
(string-map char-foldcase "AbdEgH")
==> "abdegh"
(string-map
(lambda (c)
(integer->char (+ 1 (char->integer c))))
"HAL")
==> "IBM"
(string-map
(lambda (c k)
((if (eqv? k #\u) char-upcase char-downcase)
c))
"studlycaps xxx"
"ululululul")
==> "StUdLyCaPs"
(vector-map
proc vector1 vector2 ...
)
procedure
It is an error if proc does not accept as many arguments as there
are vectors and return a single value.
The vector-map procedure applies proc element-wise to the elements of the vectors and returns a vector of the results, in order. If more than one vector is given and not all vectors have the same length, vector-map terminates when the shortest vector runs out. The dynamic order in which proc is applied to the elements of the vectors is unspecified. If multiple returns occur from vector-map, the values returned by earlier returns are not mutated.
(vector-map cadr '#((a b) (d e) (g h)))
==> #(b e h)
(vector-map (lambda (n) (expt n n))
'#(1 2 3 4 5))
==> #(1 4 27 256 3125)
(vector-map + '#(1 2 3) '#(4 5 6 7))
==> #(5 7 9)
(let ((count 0))
(vector-map
(lambda (ignored)
(set! count (+ count 1))
count)
'#(a b))) ==> #(1 2) or #(2 1)
(for-each
proc list1 list2 ...
)
procedure
It is an error if proc does not accept as many arguments as there
are lists.
The arguments to for-each are like the arguments to map, but for-each calls proc for its side ects rather than for its values. Unlike map, for-each is guaranteed to call proc on the elements of the lists in order from the first element( s) to the last, and the value returned by for-each is unspecified. If more than one list is given and not all lists have the same length, for-each terminates when the shortest list runs out. It is an error for proc to mutate any of the lists.
(let ((v (make-vector 5)))
(for-each (lambda (i)
(vector-set! v i (* i i)))
'(0 1 2 3 4))
v) ==> #(0 1 4 9 16)
(string-for-each
proc string1 string2 ...
)
procedure
It is an error if proc does not accept as many arguments as there
are strings.
The arguments to string-for-each are like the arguments to string-map, but string-for-each calls proc for its side ects rather than for its values. Unlike string-map, string-for-each is guaranteed to call proc on the elements of the lists in order from the first element(s) to the last, and the value returned by string-for-each is unspecified. If more than one string is given and not all strings have the same length, string-for-each terminates when the shortest string runs out. It is an error for proc to mutate any of the strings.
(let ((v '()))
(string-for-each
(lambda (c) (set! v (cons (char->integer c) v)))
"abcde")
v) ==> (101 100 99 98 97)
(vector-for-each
proc vector1 vector2 ...
)
procedure
It is an error if proc does not accept as many arguments as there
are vectors.
The arguments to vector-for-each are like the arguments to vector-map, but vector-for-each calls proc for its side ects rather than for its values. Unlike vector-map, vector-for-each is guaranteed to call proc on the elements of the vectors in order from the first element(s) to the last, and the value returned by vector-for-each is unspeci fied. If more than one vector is given and not all vectors have the same length, vector-for-each terminates when the shortest vector runs out. It is an error for proc to mutate any of the vectors.
(let ((v (make-list 5)))
(vector-for-each
(lambda (i) (list-set! v i (* i i)))
'#(0 1 2 3 4))
v) ==> (0 1 4 9 16)
(call-with-current-continuation
proc
)
procedure
(call/cc
proc
)
procedure
It is an error if proc does not accept one argument.
The procedure call-with-current-continuation (or its
equivalent abbreviation call/cc) packages the current
continuation (see the rationale below) as an "escape procedure"
and passes it as an argument to proc. The escape
procedure is a Scheme procedure that, if it is later called,
will abandon whatever continuation is in ect at that later
time and will instead use the continuation that was in effect
when the escape procedure was created. Calling the
escape procedure will cause the invocation of before and
after thunks installed using dynamic-wind.
The escape procedure accepts the same number of arguments as the continuation to the original call to call-with-current-continuation. Most continuations take only one value. Continuations created by the call-with-values procedure (including the initialization expressions of define-values, let-values, and let*-values expressions), take the number of values that the consumer expects. The continuations of all non-final expressions within a sequence of expressions, such as in lambda, case-lambda, begin, let, let*, letrec, letrec*, let-values, let*-values, let-syntax, letrec-syntax, parameterize, guard, case, cond, when, and unless expressions, take an arbitrary number of values because they discard the values passed to them in any event. The ect of passing no values or more than one value to continuations that were not created in one of these ways is unspecified. The escape procedure that is passed to proc has unlimited extent just like any other procedure in Scheme. It can be stored in variables or data structures and can be called as many times as desired. However, like the raise and error procedures, it never returns to its caller. The following examples show only the simplest ways in which call-with-current-continuation is used. If all real uses were as simple as these examples, there would be no need for a procedure with the power of call-with-current-continuation.
(call-with-current-continuation
(lambda (exit)
(for-each (lambda (x)
(if (negative? x)
(exit x)))
'(54 0 37 -3 245 19))
#t)) ==> -3
(define list-length
(lambda (obj)
(call-with-current-continuation
(lambda (return)
(letrec ((r
(lambda (obj)
(cond ((null? obj) 0)
((pair? obj)
(+ (r (cdr obj)) 1))
(else (return #f))))))
(r obj))))))
(list-length '(1 2 3 4)) ==> 4
(list-length '(a b . c)) ==> #f
Rationale: A common use of call-with-current-continuation is for structured, non-local exits from loops or procedure bodies, but in fact call-with-current-continuation is useful for imple- menting a wide variety of advanced control structures. In fact, raise and guard provide a more structured mechanism for non- local exits. Whenever a Scheme expression is evaluated there is a contin- uation wanting the result of the expression. The continuation represents an entire (default) future for the computation. If the expression is evaluated at the REPL, for example, then the con- tinuation might take the result, print it on the screen, prompt for the next input, evaluate it, and so on forever. Most of the time the continuation includes actions specified by user code, as in a continuation that will take the result, multiply it by the value stored in a local variable, add seven, and give the an- swer to the REPL's continuation to be printed. Normally these ubiquitous continuations are hidden behind the scenes and pro- grammers do not think much about them. On rare occasions, however, a programmer needs to deal with continuations explic- itly. The call-with-current-continuation procedure allows Scheme programmers to do that by creating a procedure that acts just like the current continuation.
(values
obj ...
)
procedure
Delivers all of its arguments to its continuation.
(call-with-values
obj
)
procedure
Calls its producer argument 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.
(call-with-values (lambda () (values 4 5))
(lambda (a b) b))
==> 5
(call-with-values * -) ==> -1
(dynamic-wind
before thunk after
)
procedure
Calls thunk without arguments, returning the result(s) of
this call. Before and after are called, also without arguments,
as required by the following rules. Note that,
in the absence of calls to continuations captured using
call-with-current-continuation, the three arguments
are called once each, in order. Before is called whenever
execution enters the dynamic extent of the call to thunk
and after is called whenever it exits that dynamic extent.
The dynamic extent of a procedure call is the period between
when the call is initiated and when it returns. The
before and after thunks are called in the same dynamic
environment as the call to dynamic-wind. In Scheme, because
of call-with-current-continuation, the dynamic
extent of a call is not always a single, connected time period.
It is defined as follows:
If a second call to dynamic-wind occurs within the dynamic extent of the call to thunk and then a continuation is invoked in such a way that the after s from these two invocations of dynamic-wind are both to be called, then the after associated with the second (inner) call to dynamic-wind is called first. If a second call to dynamic-wind occurs within the dynamic extent of the call to thunk and then a continuation is invoked in such a way that the befores from these two invocations of dynamic-wind are both to be called, then the before associated with the first (outer) call to dynamic-wind is called first. If invoking a continuation requires calling the before from one call to dynamic-wind and the after from another, then the after is called first. The ect of using a captured continuation to enter or exit the dynamic extent of a call to before or after is unspecified.
(let ((path '())
(c #f))
(let ((add (lambda (s)
(set! path (cons s path)))))
(dynamic-wind
(lambda () (add 'connect))
(lambda ()
(add (call-with-current-continuation
(lambda (c0)
(set! c c0)
'talk1))))
(lambda () (add 'disconnect)))
(if (< (length path) 4)
(c 'talk2)
(reverse path))))
==> (connect talk1 disconnect
connect talk2 disconnect)
|