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

Re: COMPILER-LET



[I've dropped common-lisp from the distribution.]

The example you give is not much different from the contrived example
in my original posting.  Here is one possible way to rewrite it:

(defmacro val (thing pname)
    (val-aux thing pname))

(eval-when (eval compile load)
    (defun val-aux (thing pname)
	(if (member thing *scoped-agents*)
	    (expand-for-agent thing pname)
	    (expand-for-hypothesis thing pname))))

(defmacro with-scoped-agent (agent &body body)
    (labels ((with-scoped-agent-aux (agent body)
		 `(macrolet ((val (thing pname)
				  (let ((*scoped-agents*
					     (cons ',agent *scoped-agents*)))
				      (val-aux thing pname)))
			     (with-scoped-agent (new-agent &body body)
				  (let ((*scoped-agents*
					     (cons ',agent *scoped-agents*)))
				      (with-scoped-agent-aux new-agent body))))
		      ,@body)))
        (with-scoped-agent-aux agent body)))


Alternatively, you can do the same thing without binding up a special
variable at all:

(defmacro val (thing pname)
    (val-aux thing pname nil))

(eval-when (eval compile load)
    (defun val-aux (thing pname scoped-agents)
	(if (member thing scoped-agents)
	    (expand-for-agent thing pname)
	    (expand-for-hypothesis thing pname))))

(defmacro with-scoped-agent (agent &body body)
    (labels ((with-scoped-agent-aux (scoped-agents body)
		 `(macrolet ((val (thing pname)
				  (val-aux thing pname ',scoped-agents))
			     (with-scoped-agent (new-agent &body body)
				  (with-scoped-agent-aux
				      (cons new-agent ',scoped-agents)
				      body)))
		      ,@body)))
        (with-scoped-agent-aux (list agent) body))


> In point of fact, an EVAL function for CL must keep around an
> environment object -- else how can it know which variables are lexical
> and know which operators are really lexical macros?  Why not just put
> the COMPILER-LETed special variables in the environemnt object--marked
> as such--then PROGV or PROGW them exactly around EVAL's macro expansion
> activity.  How could this possibly be a large change to current
> implementations?

That's a very interesting idea.  To put it more formally, you're
suggesting something along the lines of having COMPILER-LET evaluate
the value forms and store the values and variables in the environment
object, and having MACROEXPAND use the information in its environment
argument to actually bind the variables to the values, right?  That
sounds like a reasonable alternative to throwing out COMPILER-LET
entirely, but I do see a couple "gotchas" that would have to be
resolved:

* A nested COMPILER-LET should probably make sure that any bindings
established by an outer COMPILER-LET are available during the evaluation
of its value forms.

* Should the bindings made by COMPILER-LET be seen by any nested EVAL-WHENs?
What should this piece of code do in each of the eval-when situations?

(eval-when (eval compile load)
    (defvar *foo* "outside"))

(compiler-let ((*foo* "inside"))
    (eval-when (eval compile load)
        (print *foo*)))
  
-Sandra
-------