jinx@CHAMARTIN.AI.MIT.EDU (Guillermo J. Rozas) (05/03/89)
In article <8905011321.AA03861@spt.entity.com>, alms@spt.entity.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 LETREC. 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.