Path: utzoo!attcan!uunet!mcsun!ukc!edcastle!aiai!jeff From: jeff@aiai.ed.ac.uk (Jeff Dalton) Newsgroups: comp.lang.lisp Subject: Re: about EVAL Message-ID: <2722@skye.ed.ac.uk> Date: 8 Jun 90 16:25:52 GMT References: <200.266aae50@wsuiar.uucp> Reply-To: jeff@aiai.UUCP (Jeff Dalton) Organization: AIAI, University of Edinburgh, Scotland Lines: 136 In article <200.266aae50@wsuiar.uucp> mnjafar@wsuiar.uucp writes: > > I am a newcomer to lisp, so forgive my ignorance. I ran the >test programs shown below on three different machines with >Common Lisp. The results of the tests are shown below. Does >anyone out there know the answer to why Eval behaves in the way >it does. I looked in Guy Steele's book, but did not find an answer, >maybe I don't know where to look. In CLtL, you need to look at 3 Scope and Extent 5.1.2 Variables 7.1.1 Reference: 1st paragraph 7.5 Establishing New Variable Bindings 9.2 Declaration specifiers: the part on SPECIAL 20.1 Run-Time Evaluation of Forms: EVAL Pay attention to all the places where it talks about the distinction between special variables and other kinds. Then note that EVAL evaluates an expression in the current dynamic environment and a null lexical environment. Note too that global variables are the "outermost" special variables. Now suppose we do (setq x 'global-x) Then consider the following examples. They just refer to values rather than use SETQ because it's simpler. Where the local value is obtained, a SETQ would set the local value; and similarly for the global value. (let ((x 'local-x)) x) ==> local-x The LET establishes a _lexical_ variable X and gives it the value LOCAL-X. (let ((x 'local-x)) (eval 'x)) ==> global-x The LET works as before, but since EVAL uses a null lexical environment it does not "see" the local X. (let ((x 'local-x)) (declare (special x)) x) ==> local-x Here the LET establishes a _special_ variable X, because of the declaration. (let ((x 'local-x)) (declare (special x)) (eval 'x)) ==> local-x This is because EVAL uses the _current_ dynamic (ie, special variable) environment. Ok, now let's try this one: (setq x 'x0 y 'y0) (defun test () (let (x y) (declare (special y)) (setq x 'x1 y 'y1) (format t "~&X = ~S; Y = ~S~%" x y) (eval '(setq x 'x2 y 'y2)) (format t "~&X = ~S; Y = ~S~%" x y)) (format t "~&X = ~S; Y = ~S~%" x y)) After this, "(test)" will print: X = x1; Y = y1 X = x1; Y = y2 X = x2; Y = y0 What happens when test is called is: 1. The LET sets up local lexical variable X and a local special variable Y. 2. The SETQ sets the values of those same variables. 3. The EVAL of SETQ sets the global (special) X, because there is no local one, and the local (special) Y. Remember that EVAL uses the current special environment but a null lexical one. So it will see only global or local special variables. >What exactly is supposed to happen when I issue an (eval '(setq i j)) >inside a block ? What it is supposed to do is to set the global value of I to be the global value of J, just as if you typed "(setq i j)" directly to the top-level read-eval-print loop. Actually for "global value" I should really say something like "value of the current binding of the special variable". Note, however, that in your tests you do "(setq j i)" instead. ;Test1.lsp (defun strange() (let (j i xpr) (setq i 12) (setq xpr '(setq j i)) (eval xpr) (format t " ~% The value of j inside the function is :~a~%" j) ) ) Calling (strange) should result in an error saying "I" is unbound or has no global value (unless, of course, you've given it one independently. Your test2 is the same, except that you *do* give "I" a global value. By calling EVAL on (SETQ J I), you set the global value of J to be (in this case) 13. The local value of J (ie, inside the function) will be NIL, because that's what LET gives it initially. The results for Golden Common Lisp 1.01 are incorrect. What is probably happening is that it is interpreting local variables (such as those introduced by LET) as special variables. The SETQ given to EVAL affects such variables. Indeed, note that the value of J is 12 and not 13 even though in test2 you set the global value of I to 13. I suspect a more recent version of GCL would give results in line with the other Common Lisps. -- Jeff