[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Scheme Digest #111
In article <8905011321.AA03861@spt.entity.com>, firstname.lastname@example.org.COM (andrew lm shalit) writes:
> Date: 30 Apr 89 20:39:25 GMT
> From: Krulwich-Bruce@yale-zoo.arpa (Bruce Krulwich)
> A while ago I posted the suggestion that non-top-level DEFINEs do
> the same thing as top-level DEFINEs, ie, side effect the top level.
> . . .
> Most of the responses that I got said either like "well, Abelson
> and Sussman used the 'local' interpretation, so we really should
> stick to it" or "well, local non-top-level DEFINEs add fewer
> parentheses than nesting LETRECs." Does anyone have other
> (theoretical or functional) reasons for this decision??
> How about a general aversion to the notion of "top-level environment"? When
> you introduce first-class environments, and programming tools for using
> them, the notion of "top-level" starts to change. Just how it changes
> depends on how the environments and programming tools are designed.
This is a good argument against DEFINE in general, not against DEFINEs within
LETs in particular. A top-level DEFINE always assumes that you want to
side-effect the "top-level environment". What you're really saying is that
DEFINE should take an extra argument, which would explicitly specify the
environment in which the definition should take place.
The side effect in top level DEFINE is a debugging utility and purely
a consequence of interactive development systems. There is a static
way to think about top level DEFINE that eliminates this side effect:
Assume that instead of having a system with a read eval print loop, a
loader, and DEFINE modifying the read-eval-print environment or
environment of loading, we have a static compiler which reads all
modules together and then wraps a single LET around the concatenation
of all of them. Top level DEFINE now has consistent semantics with
internal DEFINE, since the LET with DEFINEs can be rewritten as a
LETREC, and there is no side effect of environments.
T does provide such a function, called *DEFINE. DEFINE is merely a
convenient syntax for doing a *DEFINE in the environment that the startup
REPL works in, called USER-ENV. The REPL-ENV can be changed as desired.
I don't think this is quite right. I believe that top level DEFINE in
T affects the loading environment, not the REPL environment. They are
the same if you give load only a file name argument. This is what top
level DEFINE does in MIT Scheme as well. You can explain the meaning
of top level DEFINE by postulating a new special form, called
THE-ENVIRONMENT, which returns the evaluation environment of the form.
Top level DEFINE would then expand into
(*DEFINE (THE-ENVIRONMENT) '<name> <value>)
To get back to the original point, it seems perfectly reasonable to allow
*DEFINEs to be nested within LETs, which would create a definition in the
environment (which is explicitly specified as an argument to the *DEFINE).
The definition is evaluated (and therefore closed) within the lexical
environment of the LET, as any other form would be.
It is perfectly reasonable, but has undesirable consequences when used
pervasively. We (at MIT) found that this "unsrestricted export" style
resulted in wired-in code, namely code that knew too much about the
shape of the environment about where it would be loaded, and could not
easily be reused.
Given that DEFINE is merely a convenient syntax for *DEFINE in the REPL-ENV,
it seems consistent to let a DEFINE with a LET be a convenient syntax for a
*DEFINE within that LET with the REPL-ENV explicitly specified as the
environment for the definition.
Unfortunately your interpretation is not correct. However, we can
make the interpretation that I have suggested above consistent merely
by stipulating that (THE-ENVIRONMENT) should "work" in all binding
contours, not merely top level environments. DEFINE would now expand
consistently (both top level and internal) as suggested above.
Using THE-ENVIRONMENT consistenly explains the behavior of all DEFINEs
as long as you restrict your internal definitions to valid LETREC
internal bindings and ignore CWCC, which also presents problems for
Local internal DEFINEs came from a variety of linguistic and
functional criteria in the design of MIT Scheme. The main linguistic
argument is that the notion of a top level is strange, and
distingushing it from internal levels is even stranger. We can get
rid of this distinction in two different ways, each accomplished by
one of the models suggested above: The global static compiler model
makes top level (and its definitions) behave exactly like the body of
a LET (and its definitions), but does not allow for interactive
development. Using THE-ENVIRONMENT makes internal contours (and
definitions therein) behave exactly like top level (with its
definitions), but presents some implementation and semantics problems.
Your suggestion for DEFINE forces the notion of top level or read eval
print loop into the language, and I think that would be a mistake. I
consider read eval print loops and "top levels" to be an environment
design issue, not something to be specified in the language.