Subject: Re: symbol in macro
From: Erik Naggum <erik@naggum.no>
Date: 02 Sep 2002 03:17:54 +0000
Newsgroups: comp.lang.lisp
Message-ID: <3239925474372819@naggum.no>

* cubicle584@mailandnews.com (Software Scavenger)
| So you export COLLECT for the sole purpose of making sure the macro
| expansion refers to the same COLLECT as the macro definition?  Is that
| a better solution than using `(... ,(intern "COLLECT") ...) ?

  I think I see your point, but let me rephrase it.  Is it the better solution
  to let macros define other local macros and functions with `macrolet´, `flet´,
  and `labels´ with symbols in the package in which the macro is defined or in
  the current package at the time of expansion?  This is a good question.

  Common Lisp has clearly made the decision that it is the better solution to
  this problem to rely on the reader for the package of the symbols than to
  attempt to control the package at macro-expansion time.  There are probably
  many reasons for this, but the ones I can think of include the fact that the
  creation of symbols has traditionally been a layered concept and has been
  taken care of by the reader quite independently from any where the symbols
  would be used in the system and the rather obvious conclusion from the
  amount of work involved in circumventing this mechanism in order to make a
  macro more package-friendly, if that is what this is about.

  However, what would it take to write macros with a conservative view to
  packages?  Let me test this on an alternative to if just for show

(defmacro if (condition then-clause &optional else-clause)
  `(cl:if ,condition
       ,(cl:if (and (listp then-clause)
                    (eq (car then-clause) (intern (symbol-name 'then))))
            `(progn ,(cdr then-clause))
          then-clause)
     ,(cl:if (and (listp else-clause)
                  (eq (car else-clause) (intern (symbol-name 'else))))
          `(progn ,(cdr else-clause))
        else-clause)))

  This is not terribly different from or more difficult than using just the
  symbols, but it needs to be done manually, or some additional macrology
  needs to be defined that sort of re-interns the symbol.  Perhaps this is
  what it should be called?

(defun re-intern (symbol)
  "Re-intern the symbol in the current package."
  (intern (symbol-name symbol) *package*))

  Now we can write

(defmacro if (condition then-clause &optional else-clause)
  `(cl:if ,condition
       ,(cl:if (and (listp then-clause)
                    (eq (car then-clause) (re-intern 'then)))
            `(progn ,(cdr then-clause))
          then)
     ,(cl:if (and (listp else-clause)
                  (eq (car else-clause) (re-intern 'else)))
          `(progn ,(cdr else-clause))
        else)))

  which is a little bit less intrusive.  I considered a macro with-reinterned
  but that left the symbols unquoted in the body and that just looked wrong.

  Suppose we want to write this with `macrolet´, instead, although we now make
  it possible to use then `then´ and `else´ too many places in the code.  It
  could look like this:

(defmacro if (condition then-clause &optional else-clause)
  `(cl:if ,condition
       (macrolet ((,(re-intern 'then) (&body forms) `(progn ,@forms)))
         ,then-clause)
     (macrolet ((,(re-intern 'else) (&body forms) `(progn ,@forms)))
        ,else-clause)))

  If it is felt to be exceptionall important to be able to do this, one might
  imagine reader-macro support for it, as well:

(defmacro if (condition then-clause &optional else-clause)
  `(cl:if ,condition
       (macrolet ((#`then (&body forms) `(progn ,@forms)))
         ,then-clause)
     (macrolet ((#`else (&body forms) `(progn ,@forms)))
        ,else-clause)))

  Is something like this in the vicinity of what you had in mind?

-- 
Erik Naggum, Oslo, Norway

Act from reason, and failure makes you rethink and study harder.
Act from faith, and failure makes you blame someone and push harder.