[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

EVAL



    Date: Wed, 26 Nov 86 00:24:12 EST
    From: Alan Bawden <ALAN@AI.AI.MIT.EDU>
    Subject:  EVAL
    To: mike%acorn@LIVE-OAK.LCS.MIT.EDU
    cc: common-lisp@SU-AI.ARPA, Fahlman@C.CS.CMU.EDU,
	Sean.Engelson@CAD.CS.CMU.EDU
    In-reply-to: Msg of Tue 25 Nov 86 02:36 est from mike%acorn at mit-live-oak.arpa
    Message-ID: <123570.861126.ALAN@AI.AI.MIT.EDU>

	Date: Tue, 25 Nov 86 02:36 est
	From: mike%acorn at mit-live-oak.arpa
	    Date: Sat, 22 Nov 86 17:32 EST
	    From: Alan Bawden <Alan@AI.AI.MIT.EDU>
	    ...  This demonstrates that LEXICAL-EVAL would have to be a new
	    special form, rather than simply a function.
	This same issue seems to come up over and over. Will someone tell
	me what is wrong with the following argument:
	    
	I see no reason for "lexical-eval" or any eval with an environment arg.
	The following is a trivial source-to-source you can use to get the 
	effect of a lexical eval:
	
	Suppose you wanted
	
	(defun foo (s-exp)  
	  (let ((x 5))
	   (flet ((bar (y) (+ x y)))
	    (block here
	     (tagbody :there
		(lexical-eval s-exp))))))
	
	this is exactly equivalent to:
	
	(defun foo (s-exp)  
	 (eval
	 `(let ((x 5))
	   (flet ((bar (y) (+ x y)))
	    (block here
	     (tagbody :there
	       ,s-exp))))))
	
	which does not use any "lexical-eval". Since the primary 
	effect of the compiler is to eliminate lexical environments, any
	lexical "stuff" surrounding a call to "lexical-eval" can't really
	be compiled (not much anyway) since it all might be referred to
	by the s-expression being evaled. This being the case, the
	second form here, which just eval's the entire lexical scope,
	is roughly as efficient. 

No, it's -roughly- equivalent to:

 (defun foo (s-exp)  
   (eval `(let ((s-exp ',s-exp))
	    (let ((x 5))
	      (flet ((bar (y) (+ x y)))
		(block here
		  (tagbody :there ,s-exp)))))))

and even then it doesn't address the issue of what happens if S-EXP 
contains code that destructively modifies the list structure in the 
object held by S-EXP. My rewrite, which at least appropriately binds
the variable S-EXP, makes that be well-behaved, which is not a
semantics-preserving transformation.

    I'm not quite sure what your proposed source transformation was supposed to
    demonstrate.  How do you compile

      (defun bind-x-then-call-f (x f)
	(funcall f `(cons x x)))

    given that anyone can do

      (bind-x-then-call-f 'foo #'lexical-eval)?

Right. Your remark about how this could be done as a special form
thwarts the ability to do this (since you can't do #'<special-form>)
and hides the potential problem in a fortuitous way. The real issue,
of course, is that this is the power people -want-. They want things
like EVAL-IN-CLOSURE, which are the problemsome cases, because the
introduction of such into the language ties the hands of the compiler
and doesn't allow any optimization.

I think Mike's intent is correct, though, in that the situations where
you might want LEXICAL-EVAL in cases that are constrained adequately so
as not to break the language are handled adequately by his suggested
rewrite using EVAL. The cases that are not handled by that rewrite --
and not at all by coincidence -- are the cases which strike fear in the
hearts of compiler maintainers everywhere.

Moreover, using LEXICAL-EVAL invites many of the name collision problems
that the move to lexical scoping did away with. 
(DEFUN F (X Y) (+ X (EVAL Y))) 
used to be a problem in dynamic lisps because the local X and Y would 
interfere with the EVAL (at least in the interpreter and also in some 
compilers). In a lexical Lisp, such as CL, the name collision problem 
doesn't happen. Allowing people to do LEXICAL-EVAL there is just asking 
for the same unwanted name collisions that we were trying to get away
with in CL.

I concur with those who have said we should explicitly document the 
rationale for the absence of this primitive in the next CL language spec.