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


Looking at what happens to the LOCAL-TYPE-DECLARE/TYPED-VAR example
we've been using may help clarify things.  Since you initially
suggested this example as being a prototypical use of COMPILER-LET, I
would think that most of what I've done with it would apply equally
well to other uses.

Your implementation using COMPILER-LET was:

(defvar *local-type-declarations* '())
(defmacro local-type-declare (declarations &body forms)
    `(compiler-let ((*local-type-declarations* 
		     (append ',declarations *local-type-declarations*)))
(defmacro typed-var (var)
    (let ((type (assoc var *local-type-declarations*)))
	(if type `(the ,(cadr type) ,var) var)))

This could be implemented using SYMBOL-MACROLET like:

(let ((temp  (gensym)))
    (defmacro local-type-declare (declarations &body forms &environment env)
	`(symbol-macrolet ((,temp  ,(append declarations
					    (symbol-macro-value temp env))))
    (defmacro typed-var (var &environment env)
	(let ((type  (assoc var (symbol-macro-value temp env))))
	    (if type `(the ,(cadr type) ,var) var)))
(defun symbol-macro-value (symbol env &optional default)
    (multiple-value-bind (expansion macro-p) (macroexpand-1 symbol env)
	(if macro-p expansion default)))

Now to answer your specific questions.

> How will the lookup routine be able to take [the name of the symbol]
> as an argument and figure out what the gensym was called?

Here, I've made it a lexical variable.  Both macros have a handle on
it and nobody else can possibly be using that symbol.  I could have
made it a special or a DEFCONSTANT instead.

> If there's a place to store that relation,
> why not just store the relation between [the symbol] and the value itself 
> rather than indirecting through an irrelevant macroexpand?

Because the macroexpand guarantees that you'll get the right value for
the -lexical- scope in which the macro -call- appears.  (Not the
dynamic scope of the call, or the lexical scope of its definition, or
any of the other possible permutations.)  The macroexpand is
definitely not "irrelevant"; it's at the very core of the technique.

> Also, somewhat unrelated but I just thought of it, the body of 
> SYMBOL-MACROLET is not (necessarily) executed at binding time, 
> while*COMPILER-LET*'s body is. I'm not sure how that will affect 
> things.  I can't convince myself that delaying the evaluation of 
> that form will have the right effect. [Even if it did, you'd need 
> to do (EVAL (MACROEXPAND ...)), not just (MACROEXPAND ...) in
> the lookup routine unless you made the simplification I alluded
> to in the previous paragraph.]

It took me a minute to figure out what you might be referring to here;
do you mean that the -value- (not body) of the symbol macro is a
literal constant?  I took care of that by having the macro that
produces the SYMBOL-MACROLET do the evaluation.  Look closely at the
backquoted expression in the two versions of LOCAL-TYPE-DECLARE.  Note
that the COMPILER-LET version could also have done the APPEND at
macroexpand time instead of including it in the macroexpansion.

Are you still confused?