440 lines
17 KiB
TeX
440 lines
17 KiB
TeX
\documentstyle[11pt,twoside]{article}
|
|
|
|
\input{code}
|
|
\input{latex-stuff}
|
|
|
|
\advance \textheight by 2ex
|
|
|
|
\begin{document}
|
|
|
|
\begin{center}
|
|
{\Large\bf The Scheme of Things:} \\
|
|
\vspace{2ex}
|
|
{\Large\bf The June 1992 Meeting$^{\hbox{\scriptsize 1}}$} \\
|
|
\vspace{3ex}
|
|
Jonathan Rees \\
|
|
Cornell University \\
|
|
{\tt jar@cs.cornell.edu}
|
|
\end{center}
|
|
|
|
\vspace{3ex}
|
|
|
|
\footnotetext[1]{To appear in {\em Lisp Pointers} V(4),
|
|
October--December 1992.}
|
|
|
|
|
|
An informally constituted group of people interested in the future of
|
|
the Scheme programming language met at the Xerox Palo Alto Research
|
|
Center on 25 June 1992. The main purpose of the meeting was to work
|
|
on the technical content of the next revision of the Scheme report.
|
|
|
|
We made progress on several fronts:
|
|
\begin{itemize}
|
|
\item Some differences with the IEEE Scheme standard were resolved.
|
|
|
|
\item Proposals for multiple return values and {\tt dynamic-wind} were
|
|
adopted.
|
|
|
|
\item A proposal for an {\tt eval} procedure was adopted.
|
|
|
|
\item The high-level macro facility described in the
|
|
Revised$^4$ Report's appendix will be moved into the report proper.
|
|
\end{itemize}
|
|
|
|
Two subcommittees were formed: one to work on exceptions, and one to
|
|
charter the formation of a standard library. The subcommittees will
|
|
report back to the group with proposals for inclusion in the report.
|
|
|
|
It had been hoped that there would be progress on some other fronts
|
|
(user-defined types, dynamic binding, improvements to ``rest''
|
|
parameters), but after inconclusive discussion these topics were
|
|
dropped. These topics will probably be taken up again in the future.
|
|
|
|
Norman Adams was appointed the Revised$^5$ Report's editor. It is
|
|
hoped that it will be ready by early 1993, so as to precede the
|
|
reconstitution of the IEEE standard group.
|
|
|
|
This article is my own interpretation of what transpired, and should
|
|
not be construed as definitive.
|
|
|
|
|
|
\piece{Agreement with the IEEE Scheme standard}
|
|
|
|
Until now, the Scheme reports have encouraged but not required the
|
|
empty list {\tt()} and the boolean false value {\tt\#f} to be
|
|
distinct. It has been the intent ever since the Revised Revised
|
|
Report, however, that this distinction would eventually be required.
|
|
The IEEE Scheme standard bit the bullet in 1990, and now the
|
|
Revised$^5$ report follows.
|
|
|
|
The standard also dropped the distinction between essential and
|
|
not-essential language features; most features that were formerly not
|
|
essential, such as n-ary {\tt+} and {\tt apply}, are now required.
|
|
The Revised$^5$ Report will adopt this stance, at least as regards
|
|
language features that are shared with the IEEE standard.
|
|
Non-essential non-IEEE oddities such as {\tt transcript-on} and {\tt
|
|
transcript-off} and the proposed {\tt interaction-\ok{}environment} (see
|
|
below) were not discussed at the meeting, however, and consensus on
|
|
their status will have to be reached via electronic mail.
|
|
|
|
A third aspect of the standard that was adopted was a certain obscure
|
|
paragraph regarding assignments to top-level variables (section 6,
|
|
paragraph 2). The effect of this is that if a program contains an
|
|
assignment to any top-level variable, then the program must contain a
|
|
{\tt define} for that variable; it is not sufficient that the variable
|
|
be bound. This has been the case for most variables, but the rule
|
|
applies as well to variables such as {\tt car} that have built-in
|
|
bindings. In addition, it is clarified that if a program makes such a
|
|
definition or assignment, then the behavior of built-in procedures
|
|
will not be affected. For example, redefining {\tt length} cannot
|
|
affect the behavior of the built-in {\tt list->vector} procedure.
|
|
If in some particular implementation {\tt list->vector} is written
|
|
in Scheme and calls {\tt length}, then it must be sure to call the
|
|
built-in {\tt length} procedure, not whatever happens to be the value
|
|
of the variable {\tt length}.
|
|
|
|
|
|
\piece{Multiple return values}
|
|
|
|
The {\tt call-with-values} and {\tt values} procedures were described
|
|
in an earlier Scheme of Things ({\em Lisp Pointers}, volume IV, number
|
|
1), but I'll review them here. The following is adapted from John Ramsdell's
|
|
concise description:
|
|
|
|
\begin{list}{}{}{}\item
|
|
{\tt(values \var{object} $\ldots$)}
|
|
\hfill {\rm essential procedure}
|
|
|
|
{\tt values} delivers all of its arguments to its continuation.
|
|
|
|
\vspace{2ex}
|
|
|
|
{\tt(call-with-values \var{thunk} \var{receiver})}
|
|
\hfill {\rm essential procedure}
|
|
|
|
{\tt call-with-values} calls its \var{thunk} argument with a
|
|
continuation that, when passed some values, calls the
|
|
\var{receiver} procedure with those values as arguments.
|
|
The continuation for the call to \var{receiver} is the
|
|
continuation of the call to {\tt call-with-values}.
|
|
\end{list}
|
|
|
|
Except for continuations created by the {\tt call-with-values}
|
|
procedure, all continuations take exactly one value, as now; the
|
|
effect of passing no value or more than one value to continuations
|
|
that were not created by {\tt call-with-values} is unspecified (as
|
|
indeed it is unspecified now).
|
|
|
|
{\tt values} might be defined as follows:
|
|
\begin{code}
|
|
(define (values . things)
|
|
(call-with-current-continuation
|
|
(lambda (cont) (apply cont things))))
|
|
\end{code}
|
|
That is, the procedures supplied by {\tt
|
|
call-with-current-continuation} must be passed the same number of
|
|
arguments as values expected by the continuation.
|
|
|
|
Because the behavior of a number-of-values mismatch between a
|
|
continuation and its invoker is unspecified, some implementations may
|
|
assign some specific meaning to such situations; for example, extra
|
|
values might be ignored, or defaults might be supplied for missing
|
|
values. Thus this multiple return value proposal is compatible with
|
|
Common Lisp's multiple values, but strictly more conservative than it.
|
|
The behavior of programs in such situations was a point of contention
|
|
among the authors, which is why only the least common denominator
|
|
behavior was specified.
|
|
|
|
|
|
\piece{Unwind/wind protection}
|
|
|
|
{\tt dynamic-wind}, which was described previously in this column (when it
|
|
was The Scheme Environment; {\em Lisp Pointers}, volume I, number 2),
|
|
is already implemented in many Scheme dialects. {\tt dynamic-wind}
|
|
takes three arguments, all of which are thunks (procedures of no arguments).
|
|
It behaves as if it were defined with
|
|
\begin{code}
|
|
(define (dynamic-wind before during after)
|
|
(before)
|
|
(call-with-values during
|
|
(lambda results
|
|
(after)
|
|
(apply values results))))
|
|
\end{code}
|
|
except that the execution of the {\tt during} thunk is ``protected''
|
|
against non-local entries and exits: a throw out of the execution
|
|
of {\tt during} will cause the {\tt after} thunk to be invoked, and a
|
|
throw from outside back in will cause the {\tt before} thunk to be
|
|
invoked. (By ``throw'' I mean an invocation of an explicit
|
|
continuation as obtained from {\tt call-with-current-continuation}.)
|
|
|
|
For details, the earlier Scheme Environment column refers the reader
|
|
to Friedman and Haynes's paper ``Constraining Control'' in POPL 1985,
|
|
but to save you the trouble of looking that up, I have supplied a more
|
|
direct implementation of {\tt dynamic-wind} in an appendix to the
|
|
present column.
|
|
|
|
{\tt dynamic-wind} was adopted with the following clarifications: The
|
|
semantics of {\tt(dynamic-wind \var{before} \var{during} \var{after})}
|
|
should leave unspecified what happens if a throw occurs out of {\em
|
|
before} or {\em after}\/; and it is best to defer interrupts during {\em
|
|
before} and {\em after}.
|
|
|
|
|
|
|
|
\piece{Evaluating computed expressions}
|
|
|
|
The original 1975 memo on Scheme described {\tt evaluate},
|
|
which was analogous to Lisp's traditional {\tt eval} function. {\tt
|
|
evaluate} took a single argument, an S-expression, and invoked an
|
|
interpreter on it. For example:
|
|
\begin{code}
|
|
(let ((name '+)) (evaluate (list name 2 3)))
|
|
\ev 5
|
|
\end{code}
|
|
Scheme being lexically scoped, however, there was some confusion over
|
|
which environment the expression was to be evaluated in. Should
|
|
\begin{code}
|
|
(let ((name '+))
|
|
(let ((+ *))
|
|
(evaluate (list name 2 3))))
|
|
\end{code}
|
|
evaluate to 5 or to 6?
|
|
|
|
To clarify matters, the Revised Report replaced {\tt evaluate} with
|
|
{\tt enclose}, which took two arguments, a {\tt lambda}-expression and
|
|
a representation of an environment from which to supply bindings of the
|
|
{\tt lambda}-expression's free variables. For example:
|
|
\begin{code}
|
|
(let ((name '+))
|
|
(let ((+ *))
|
|
((enclose (list 'lambda '() (list name 2 3))
|
|
(list (cons '+ +))))))
|
|
\ev 6
|
|
\end{code}
|
|
This forced the programmer to be explicit about the {\tt
|
|
lambda}-expression's enclosing environment.
|
|
|
|
For various technical and practical reasons, there was no {\tt eval}
|
|
analogue in subsequent Scheme reports. The major stumbling blocks
|
|
were how to describe {\tt eval} formally and how to define something
|
|
that makes sense in all extant variants of the language. Some Scheme
|
|
implementations contain a distinguished top-level environment, while
|
|
others extend the language by providing ways to create multiple
|
|
environments, any of which might serve equally well.
|
|
|
|
The {\tt eval} proposal adopted at the June meeting, which I reproduce
|
|
here, is one that comes from Bill Rozas.
|
|
|
|
\begin{list}{}{}{}\item
|
|
|
|
{\tt(eval \var{expression} \var{environment-specifier})}
|
|
\hfill {\rm essential procedure}
|
|
|
|
{\tt eval} evaluates \var{expression} in the environment indicated
|
|
by {\em environment-\discretionary{}{}{}specifier}. {\em
|
|
environment-specifier} may be the return value of one of the three
|
|
procedures described below, or implementation-specific extensions.
|
|
No other operations on environment specifiers are defined by this
|
|
proposal.
|
|
|
|
Implementations may allow non-expression programs (i.e.\
|
|
definitions) as the first argument to {\tt eval} \var{only} when
|
|
the second argument is the return value of {\tt interaction-environment}
|
|
or some implementation extension. In other words, {\tt eval} will never
|
|
create new bindings in the return value of {\tt null-environment} or
|
|
{\tt scheme-report-environment}.
|
|
|
|
\vspace{2ex}
|
|
|
|
{\tt(scheme-report-environment \var{version})}
|
|
\hfill {\rm essential procedure}
|
|
|
|
{\em Version} must be an exact non-negative integer corresponding to a
|
|
version of one of the Revised$^n$ Reports on Scheme. This procedure
|
|
returns a specifier for an environment that contains exactly the
|
|
set of bindings specified in the corresponding report that the
|
|
implementation supports. Not all versions may be available in all
|
|
implementations at all times. However, an implementation that
|
|
conforms to version $n$ of the Revised$^n$ Reports on Scheme must
|
|
accept version $n$. If {\tt scheme-report-environment} is
|
|
available, but the specified version is not, the procedure will
|
|
signal an error.
|
|
|
|
The effect of assigning (through the use of {\tt eval}) a variable
|
|
bound in a {\tt scheme-report-environment} (e.g.\ {\tt car}) is
|
|
unspecified. Thus the environments specified by the return
|
|
values of {\tt scheme-report-environment} may be immutable.
|
|
|
|
\vspace{2ex}
|
|
|
|
{\tt(null-environment)}
|
|
\hfill {\rm essential procedure}
|
|
|
|
This procedure returns a specifier for an environment that contains no
|
|
variable bindings, but contains (syntactic) bindings for all the
|
|
syntactic keywords defined in the report, and no others.
|
|
|
|
\vspace{2ex}
|
|
%\newpage %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
|
|
{\tt(interaction-environment)}
|
|
\hfill {\rm procedure}
|
|
|
|
This procedure returns a specifier for an environment that
|
|
contains imple\-men\-ta\-tion-defined bindings, typically a superset of
|
|
those listed in the report. The intent is that this procedure
|
|
will return a specifier for the environment in which the
|
|
implementation would evaluate expressions dynamically typed by the
|
|
user.
|
|
|
|
\end{list}
|
|
|
|
Rozas explains:
|
|
``The proposal does not imply the existence or support of first-class
|
|
environments, although it is compatible with them.
|
|
The proposal only requires a way of associating tags with a finite set
|
|
of distinguished environments which the implementations can maintain
|
|
implicitly (without reification).
|
|
|
|
``\,`Pascal-like' implementations can support both {\tt null-environment} and
|
|
%\penalty0
|
|
{\tt scheme-report-environment} since the environments specified by
|
|
the return values of these procedures need not share any bindings with
|
|
the current program. A version of {\tt eval} that supports these but
|
|
not {\tt interaction-environment} can be written portably,
|
|
but can be better written by the implementor, since it can share code
|
|
with the default evaluator or compiler.''
|
|
|
|
Here ``Pascal-like'' refers to implementations that are restricted to
|
|
static compilation and linking. Because an {\tt eval} that doesn't
|
|
support
|
|
\penalty0
|
|
{\tt interaction-\discretionary{}{}{}environment} can be written
|
|
entirely in the Scheme language described by the rest of the report,
|
|
it raises no troublesome questions about its formal semantics.
|
|
|
|
|
|
\piece{Macros}
|
|
|
|
The consensus of the meeting was that {\tt define-syntax}, {\tt
|
|
syntax-rules}, {\tt let-\discretionary{}{}{}syntax}, and {\tt
|
|
letrec-syntax} should be moved out of the report's appendix into the
|
|
main body of the report. Although everyone agrees that a low-level
|
|
macro facility is important, the subject is too contentious at
|
|
present, with three or more competing proposals at present. The
|
|
disposition of the rest of the appendix and of the other low-level
|
|
proposals will be left up to the report's editor.
|
|
|
|
|
|
\piece{Committee work}
|
|
|
|
There is a strong sense that some kind of exception system is needed.
|
|
However, no specific proposal was ready at the time of the meeting. A
|
|
committee has been formed to work on one. What seems to be in the
|
|
air might be described as a highly distilled version of the condition
|
|
system that Kent Pitman developed for Common Lisp. I hope that I'll
|
|
be able to report on this in a future column.
|
|
|
|
|
|
On the subject of libraries, Will Clinger's minutes report that
|
|
``the authors perceive a need to give some library official status. In
|
|
fact, we need to give official sanction to multiple libraries. There
|
|
is reason to distinguish between accepted (or standard) libraries,
|
|
experimental libraries, and proposals. The accepted libraries can
|
|
reduce the intellectual size of the language by removing things like
|
|
{\tt string->list} from the report. The experimental libraries would
|
|
contain solid implementations of experimental features, including
|
|
things that might never deserve to be in the report. The proposal
|
|
libraries could contain anything implemented in portable Scheme.''
|
|
|
|
|
|
Among the content of the accepted libraries, some features (such as
|
|
those that may be moved out of the body of the report) may be required
|
|
to be built in to implementations, while others will be expected to be
|
|
available on demand (perhaps using something similar to, but not the
|
|
same as, {\tt require} as found in Common Lisp and GNU Emacs).
|
|
|
|
A librarian was appointed (Rees), and a library committee is
|
|
developing proposals for the charter, structure, and content of the
|
|
libraries.
|
|
|
|
|
|
\separator
|
|
|
|
I would like to acknowledge Will Clinger, who prepared the minutes of
|
|
the meeting, and the various people who contributed proposals,
|
|
including Bill Rozas and John Ramsdell. Any errors here are my
|
|
responsibility, however. Thanks also to Norman Adams and Richard
|
|
Kelsey for corrections to a draft of this article.
|
|
|
|
I would also like to belatedly acknowledge Norman Adams, Pavel
|
|
Curtis, Bruce Donald, and Richard Kelsey for their comments on drafts of
|
|
my previous column.
|
|
|
|
For future columns, I am entertaining various topic possibilities,
|
|
including {\tt eval}, threads, {\tt amb}, and monads.
|
|
If you have other ideas, and particularly if you think the written
|
|
record on the language is particularly poor in certain areas, please
|
|
write and let me know.
|
|
|
|
\vspace{2ex}
|
|
|
|
%\newpage
|
|
|
|
%\bgroup \small
|
|
|
|
\piece{Appendix: An implementation of {\tt dynamic-wind}}
|
|
|
|
This program is based on my vague recollection of an ancient
|
|
manuscript by Chris Hanson and John Lamping. I apologize for the lack
|
|
of data abstraction, but the code is more concise this way.
|
|
|
|
A state space is a tree with the current state at the root. Each node other
|
|
than the root is a triple $\langle\var{before}, \var{after},
|
|
\var{parent}\rangle$, represented in this implementation as two pairs
|
|
{\tt((\var{before} .\ \var{after}) .\ \var{parent})}.
|
|
Navigating between states requires re-rooting the tree by reversing
|
|
parent-child links.
|
|
|
|
Since {\tt dynamic-wind} interacts with {\tt
|
|
call-with-current-continuation}, this implementation must replace the
|
|
usual definition of the latter.
|
|
|
|
\begin{code}
|
|
(define *here* (list #f))
|
|
\codeskip
|
|
(define original-cwcc call-with-current-continuation)
|
|
\codeskip
|
|
(define (call-with-current-continuation proc)
|
|
(let ((here *here*))
|
|
(original-cwcc (lambda (cont)
|
|
(proc (lambda results
|
|
(reroot! here)
|
|
(apply cont results)))))))
|
|
\codeskip
|
|
(define (dynamic-wind before during after)
|
|
(let ((here *here*))
|
|
(reroot! (cons (cons before after) here))
|
|
(call-with-values during
|
|
(lambda results
|
|
(reroot! here)
|
|
(apply values results)))))
|
|
\codeskip
|
|
(define (reroot! there)
|
|
(if (not (eq? *here* there))
|
|
(begin (reroot! (cdr there))
|
|
(let ((before (caar there))
|
|
(after (cdar there)))
|
|
(set-car! *here* (cons after before))
|
|
(set-cdr! *here* there)
|
|
(set-car! there #f)
|
|
(set-cdr! there '())
|
|
(set! *here* there)
|
|
(before)))))
|
|
\end{code}
|
|
|
|
%\egroup
|
|
|
|
\end{document}
|