Path: utzoo!news-server.csri.toronto.edu!cs.utexas.edu!uunet!stanford.edu!snorkelwacker.mit.edu!ai-lab!zurich.ai.mit.edu!jinx From: jinx@zurich.ai.mit.edu (Guillermo J. Rozas) Newsgroups: comp.lang.scheme Subject: Re: EVAL in Scheme Message-ID: Date: 5 Mar 91 21:23:03 GMT References: <13781@asylum.SF.CA.US> <1991Mar5.160735.24566@rock.concert.net> Sender: news@ai.mit.edu Reply-To: jinx@zurich.ai.mit.edu Organization: M.I.T. Artificial Intelligence Lab. Lines: 88 In-reply-to: hayes@jazz.concert.net's message of 5 Mar 91 16:07:35 GMT Feeley's example seems to suggest there is something uniquely weird about the global environment. But if I understand what's going on here--and admittedly my confidence is not terribly high on that point--the same problem would arise with an attempt to access a variable in *any* lexically enclosing environment. For example, (let ((z 50)) (begin (EVAL '(set! z (+ z z))) (write z))) ought to cause the same trouble. We can teach our EVAL how to bind variables that are created within its own scope, but it doesn't know where to look for the values of variables anywhere outside that scope. Doesn't this line of reasoning lead to the conclusion that EVAL is inextricably part of the interpreter, rather than something we can add on to an existing interpreter? EVAL has to know how environments are represented internally. Hence it seems the only way to write EVAL within Scheme is to write an entire Scheme within Scheme. Facilities for finding global variables--but not local variables introduced in enclosing scopes--would not be enough. Some implementations of Scheme have first-class environments. That is, they provide a way to reify an existing environment into an object that can be used later. They also provide some procedures for accessing variables, assigning variables, and defining variables in environment objects. In these implementations, EVAL typically takes two arguments, namely the expression to evaluate and the environment with respect to which the evaluation should be done. A common extension is to default the second argument to the environment where the current read-eval-print loop is evaluating. In MIT Scheme, for example, (let ((z 50)) (begin (EVAL '(set! z (+ z z))) (write z))) would request evaluation with respect to the read-eval-print loop's environment, which would probably result in an error, while (let ((z 50)) (begin (EVAL '(set! z (+ z z)) (the-environment)) (write z))) would request evaluation with respect to the environment where the form (THE-ENVIRONMENT) is evaluated, and would therefore print 100. Besides the special form (THE-ENVIRONMENT), MIT Scheme has some procedures for manipulating environments: (lexical-reference ) is equivalent to (EVAL ) (lexical-assignment ) is equivalent to (EVAL `(SET! , ',) ) and (local-assignment ) is equivalent to (EVAL `(DEFINE , ',) ) Environment objects are otherwise opaque, ie. their representation is hidden, and CAR, VECTOR-REF, etc. do not work on them. The EVAL provided by MIT Scheme is provided primitively, but it need not be. Given these primitives (and a way to obtain the current read-eval-print loop's evaluation environment), EVAL can be written in user code. T has similar procedures for manipulating environments, but the way to reify environments is different and somewhat better suited to compilation. PS: This is not a plug for first-class environments, just a description of one of the options.