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


First, I was hoping for a clear statement of what nested backquotes
meant.  Here's my current theory - the result of experimentation.
I don't see how to interpret CLtL to mean this (innermost backquote
expanded first??), but at least maybe someone in the know can
either confirm my theory (and provide the mapping from CLtL) or
correct it (and still provide the mapping):

When you evaluate a backquote expression (oh, all right, the 
result of reading one evaluates as if ...), you throw away the
backquote (we're always evaluating the "outermost" backquote now!),
find all the "matching" commas (which must all be innermost
commas, although not all innermost commas match this backquote!)
and replace them with the results of evaluating them.  Leave all
other backquotes and commas (and everything else) alone!  Thus
``(a ,s ,',d ,,f `(,g)) 
          --  --
results in evaluation of the underlined expressions, yielding 
something like
 `(a ,s ,'4 ,7 `(,g))
,@ is just like , except that you throw out an outer pair of parens.

Is that right?
Next some comments on the "solutions".  What they have done is to
change the protected-+ macro from what I would have written 
originally into something else - my ((x ,x) (y ,y)) has become a
mapcar.  In other words, as long as the expansion has to be 
evaluated again, we can replace what we really want with something
else which will later evaluate to the same thing.  This works, but
starts to sacrifice some of the clarity which was the reason for
backquote in the first place.

I think it would be a lot easier if you COULD "pass a 'free' comma 
around", and more generally, if you could directly express when
each expression should be evaluated, i.e., which backquote it
went with.  Here's a "labelled backquote" macro that does this.  
Reviews are welcome.  I describe it as a regular macro, not a 
readmacro.  I wonder whether that's important.  Perhaps backquote
could be extended in this direction.
(LBQ <label> ...) finds all occurrences of |,| (|,@|) which
are followed by <label>, throws out the |,| and label and replaces
the following expression with its value.  

(defmacro define-protected (function &rest args)
  (LBQ outer defmacro |,| outer (MAKE-PROTECTED-NAME function)
      |,| outer (mapcar #'cadr args)
     (LBQ inner let |,| outer (BUILD-LET-LIST args)
	(and |,@| outer args
	     |,| outer (BUILD-FUNCTION-CALL function args)))))

where BUILD-LET-LIST produces a list of the form
((x |,| inner x) (y |,| inner y)):
Note that with backquote I couldn't have removed this into another
function - sort of reminds you of lexical scoping, huh?

(defun BUILD-LET-LIST (args)
  (mapcar #'(lambda (arg) (list (cadr arg) '|,| 'inner (cadr arg))) args))
(defun BUILD-FUNCTION-CALL (function args)
       (cons function (mapcar #'cadr args)))

(macroexpand-1 '(define-protected + (numberp x) (numberp y)))
	  (X Y)
	      ((X |,| INNER X) (Y |,| INNER Y))
	      (AND (NUMBERP X) (NUMBERP Y) (+ X Y))))