This SRFI is currently in final status. Here
explanation of each status that a SRFI can hold. To provide
input on this SRFI, please send email
To subscribe to the list,
instructions. You can access previous messages via the
parameterizedeal with the dynamic extent indirectly. The same holds true for the procedures and syntaxes dealing with continuation marks as defined by SRFI 157. This SRFI reifies the dynamic extent into a first-class value together with a well-defined procedural interface and a syntax to create procedures that remember not only their environment at creation time but also their dynamic extent, which includes their dynamic environment.
While the Scheme language is rich enough to reify the concept of the dynamic extent of a procedure — the sample implementation accompanying this SRFI is a proof of this fact — there is no standard for how such a reification is exposed to the user. It is the purpose of this SRFI to remedy this. In particular, Scheme systems may provide faster implementations than the portable sample implementation of this SRFI.
To give an example why explicit handling of dynamic extents can become necessary, let us consider the following two definitions:
(define (safe-sqrt error-handler) (lambda (x) (when (negative? x) (error-handler "negative argument")) (sqrt x))) (define (error-handler msg) (display msg (current-error-port)) (newline (current-error-port)) 'error) (define my-safe-sqrt (safe-sqrt error-handler))
(my-safe-sqrt -1) is executed, an error
message is printed on the current error port of the call
my-safe-sqrt. It may, however, have been the
intention of the user that the message is printed to whatever
error port was current when the
error-handler was defined. Using the
syntax of this SRFI, this can be achieved by changing the
(define error-handler (dynamic-lambda (msg) (display msg (current-error-port)) (newline (current-error-port)) 'error))
The same goes not only for error handlers, but for any other
type of callback procedure where it often makes sense to
reinstate the dynamic extent of the definition of the
callback for the dynamic extent of the call to the
callback, e.g. to define the callback
dynamic-lambda as opposed to using a
In case the error handler from the example above wants to call back on a provided continuation, we have to be a bit more careful so that the continuation is called in the expected dynamic extent:
(define (safe-sqrt error-handler) (lambda (x) (when (negative? x) (error-handler "negative argument" exit)) (sqrt x))) (define error-handler (let ((dynamic-extent (current-dynamic-extent))) (lambda (msg exit) (with-dynamic-extent dynamic-extent (lambda () (display msg (current-error-port)) (newline (current-error-port)))) (exit 'error)))) (define my-safe-sqrt (safe-sqrt error-handler))
Note that the example of the error handler above is meant as a
minimal example in order to demonstrate the capabilities of this
library. It is not an example that cannot easily be rewritten
in Scheme code not making use of this SRFI, e.g. by
taking a snapshot of the value
current-error-port in form of a lexical
variable. However, note that in general more than one parameter
object may be accessed in the dynamic extent of the body of
dynamic-lambda or that they are not necessarily
known. In the presence
39 parameter objects, which are mutable, the technique of
taking a snapshot of the current value won't work. Finally, the
dynamic extent can be much more complicated than just about
parameter objects. For example, there could be global state that
is set up and restored by
dynamic-wind. In all
these cases, this SRFI provides the cleanest solution.
Another use case
155, which provides a specification and an implementation of
promises such that lazy algorithms using them work well in the presence
call-with-current-continuation and dynamically
Throughout, we reuse the term dynamic extent for a reified
dynamic extent. In this sense, the
thunk of a call to
sets up the dynamic extent of the call
after thunk restores the dynamic
extent of the call to
Dynamic extents form a type not necessarily disjoint from other Scheme types.
An R7RS system implementing this SRFI shall export the
following procedures and the syntax under the library
#t if its argument is a dynamic extent,
#f otherwise. Note that dynamic extents are not
necessarily disjoint from other Scheme types such as procedures.
current-dynamic-extent procedure returns
the current dynamic extent by capturing the dynamic extent
of the call to
can be reinstated by the
(with-dynamic-extent dynamic-extent thunk)
with-dynamic-extent procedure calls
thunk and returns the values yielded
thunk. The call
thunk happens in the dynamic extent
captured by the
(dynamic-lambda <formals> <body>)
dynamic-lambda expression is equivalent
lambda expression except that not only the
environment but also the dynamic extent in effect when the
dynamic-lambda expression was evaluated is
In other words, the expression
<formals> <body>) closes also over the
Any Scheme system implementing both SRFI 154 and SRFI 157 shall also define the following procedures.
An R7RS system shall export these procedures under
(srfi 157 key) library name.
Note: It also makes sense for a Scheme system that only implements the continuation marks of SRFI 157 and not the first-class dynamic extents described in this document to implement the following procedures.
make-continuation-mark-key procedure returns
an object that can be used as a key for continuation marks. The
returned object is guaranteed to be different (in the sense
eq?) from any other existing Scheme object
including other Scheme objects returned by previous or future
obj is a Scheme
object that was returned by a previous invocation
Rationale: Continuation marks can associate values with
arbitrary keys, not just keys created
continuation marks associated with keys created
make-continuation-mark-key can be more
efficient because the implementation is free to store
arbitrary metadata inside the key, which it can use to
implement continuation marks associated with these keys more
Therefore, it is generally recommended to use continuation
marks with these keys.
returns an object that can be used as a key for continuation
marks, called a shallow key. The returned object is guaranteed to be different (in
the sense of
eq?) from any other existing Scheme
object including other Scheme objects returned by previous or
future invocations of
The set of continuation marks returned by the
defined in SRFI 157) retains not the full list of all
continuation mark values associated with a shallow key but this
list truncated after the first element. (For any other type of
key, the set of continuation marks contains the full list of all
continuation mark values.)
obj is a Scheme
object that was returned by a previous invocation
Rationale: Often, user code is only interested in the latest
continuation mark value associated with a key, that is the
continuation-mark-set->list is used.
(The implementation of parameter objects in SRFI 157 is an
example.) In conjunction with the first-class dynamic extents
of this SRFI, this can lead to space leaks
current-dynamic-extent generally has to
capture all continuation mark values and not only the latest.
For continuation marks associated with shallow keys,
current-dynamic-extent only needs to
retain the latest values.
The sample implementation is provided
as an R7RS library. It should be easily adaptable to any Scheme
implementation as long as that implementation has a concept of
call-with-current-continuation, and has a
macro facility (for implementing
The sample implementation includes a special algorithm for use with Chibi Scheme. This serves as a demonstration how efficient implementations of this specification can be provided by Scheme implementers.
A full implementation of this specification (including an
implementation of SRFI 157 and its extension described here) is
provided in the form of a meta-circular interpreter written in
R7RS dubbed Inferior Scheme,
which is a REPL for the Scheme IEEE 1178-1990 standard. Outside
of the standard syntax and procedures, Inferior Scheme provides
the syntax and the procedures of SRFIs 154, 155, and 157, the
procedure of the R4RS,
dynamic-wind of R5RS,
Thanks go to the SRFI editor for keeping the SRFI process alive and running. Special thanks go to Jim Rees for playing with and testing this proposed specification. Fruitful discussions with him led to the definition of shallow keys to prevent space leaks in SRFI 155 and other use cases.
Copyright (C) Marc Nieper-Wißkirchen (2017, 2018). All Rights Reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.