From: Simon Katz
Subject: Expand a macrolet form?
Date: 
Message-ID: <a5r9dp$9hm60$1@ID-131024.news.dfncis.de>
Is there a way of obtaining the expansion of a MACROLET form?

For a macro defined using DEFMACRO, I can use MACROEXPAND:

  (defmacro my-list-1 (x y)
    `(list ,x ,y))

  (macroexpand '(my-list-1 a b))
  => (LIST A B)

But is there a way of producing the form (LIST A B) from the
following:

  (macrolet ((my-list-2 (x y)
               `(list ,x ,y)))
    (my-list-2 a b))

From: Thomas F. Burdick
Subject: Re: Expand a macrolet form?
Date: 
Message-ID: <xcvr8n2po2d.fsf@apocalypse.OCF.Berkeley.EDU>
"Simon Katz" <·····@nomistech.com> writes:

> Is there a way of obtaining the expansion of a MACROLET form?
> 
> For a macro defined using DEFMACRO, I can use MACROEXPAND:
> 
>   (defmacro my-list-1 (x y)
>     `(list ,x ,y))
> 
>   (macroexpand '(my-list-1 a b))
>   => (LIST A B)
> 
> But is there a way of producing the form (LIST A B) from the
> following:
> 
>   (macrolet ((my-list-2 (x y)
>                `(list ,x ,y)))
>     (my-list-2 a b))
> 

Common Lisp doesn't include a code-walker in the spec, however, your
implementation may come with one.  If you use CMUCL, you can use the
code walker that comes with PCL:

  * (walker:macroexpand-all
      '(macrolet ((my-list-2 (x y)
                   `(list ,x ,y)))
        (my-list-2 a b)))
  (MACROLET ((MY-LIST-2 (X Y)
               `(LIST ,X ,Y)))
    (LIST A B))

If you use another implementation, you can check to see if it has
similar facilities, and, if not, use something like Kent's suggestion.

-- 
           /|_     .-----------------------.                        
         ,'  .\  / | No to Imperialist war |                        
     ,--'    _,'   | Wage class war!       |                        
    /       /      `-----------------------'                        
   (   -.  |                               
   |     ) |                               
  (`-.  '--.)                              
   `. )----'                               
From: Jochen Schmidt
Subject: Re: Expand a macrolet form?
Date: 
Message-ID: <a5rnte$o8k$1@rznews2.rrze.uni-erlangen.de>
Thomas F. Burdick wrote:

> Common Lisp doesn't include a code-walker in the spec, however, your
> implementation may come with one.  If you use CMUCL, you can use the
> code walker that comes with PCL:
> 
>   * (walker:macroexpand-all
>       '(macrolet ((my-list-2 (x y)
>                    `(list ,x ,y)))
>         (my-list-2 a b)))
>   (MACROLET ((MY-LIST-2 (X Y)
>                `(LIST ,X ,Y)))
>     (LIST A B))
> 
> If you use another implementation, you can check to see if it has
> similar facilities, and, if not, use something like Kent's suggestion.

In LispWorks walker:macroexpand-all is called walker:walk-form and can be 
used in the same way like your example showed.

ciao,
Jochen

--
http://www.dataheaven.de
From: Kent M Pitman
Subject: Re: Expand a macrolet form?
Date: 
Message-ID: <sfwwuwu20jm.fsf@shell01.TheWorld.com>
"Simon Katz" <·····@nomistech.com> writes:

> Is there a way of obtaining the expansion of a MACROLET form?
> 
> For a macro defined using DEFMACRO, I can use MACROEXPAND:
> 
>   (defmacro my-list-1 (x y)
>     `(list ,x ,y))
> 
>   (macroexpand '(my-list-1 a b))
>   => (LIST A B)
> 
> But is there a way of producing the form (LIST A B) from the
> following:
> 
>   (macrolet ((my-list-2 (x y)
>                `(list ,x ,y)))
>     (my-list-2 a b))

You need to get inside a macro expander and call MACROEXPAND-1 with the
lexical environment.  Here's a possible example:

(defmacro debug-macro (form &environment env)
  (let ((expansion (macroexpand-1 form env)))
    ;; Do the expansion first and then bind *print-pretty* in case
    ;; the expansion is sensitive to the binding of that variable.
    (let ((*print-pretty* t))
      (format t "~S~%==> ~S" form expansion))
    ;; Return the original form, not the expansion, in case the caller
    ;; is himself calling MACROEXPAND-1 and wants to have some special
    ;; action based on partial expansions (as happens with SETF, for
    ;; some cases).
    form))

(let ((a 3) (b 4))
  (macrolet ((my-list-2 (x y)
               `(list ,x ,y)))
    (debug-macro
      (my-list-2 a b))))
(MY-LIST-2 A B)
==> (LIST A B)
=> (3 4)

Of course, the example shown is the typeout when you do this interactively.
If you file compile this, the macro debugging info will come out at compile
time and no output will occur at runtime.

If you want to have the value at runtime, and not to execute the code,
you might try:

(defmacro macroexpansion-of (form &environment env)
  `',(macroexpand-1 form env))

(macrolet ((my-list-2 (x y)
             `(list ,x ,y)))
  (macroexpansion-of (my-list-2 a b)))
=> (LIST A B)

Note that there is no way to get the expansion from the "outside" without
writing a codewalker.  That's what it means for the information to be lexical.
The good (and in this case bad) thing about lexical is that it resists 
intrusion from outsiders who do not have direct access to the actual
source code.  That's called data privacy.  If you have access to the code,
you can use a codewalker... but CL doesn't come with one, and I think it's
quite a lot more work than you want or need to do just to debug code.
From: Simon Katz
Subject: Re: Expand a macrolet form?
Date: 
Message-ID: <a60uvg$ajvja$1@ID-131024.news.dfncis.de>
> "Kent M Pitman" <······@world.std.com> writes:
> "Simon Katz" <·····@nomistech.com> writes:
>
> > Is there a way of obtaining the expansion of a MACROLET form?
> >
> > For a macro defined using DEFMACRO, I can use MACROEXPAND:
> >
> >   (defmacro my-list-1 (x y)
> >     `(list ,x ,y))
> >
> >   (macroexpand '(my-list-1 a b))
> >   => (LIST A B)
> >
> > But is there a way of producing the form (LIST A B) from the
> > following:
> >
> >   (macrolet ((my-list-2 (x y)
> >                `(list ,x ,y)))
> >     (my-list-2 a b))
>
> You need to get inside a macro expander and call MACROEXPAND-1 with
> the lexical environment.
> [Examples and discussion deleted.]

Thanks Kent -- that was exactly the help I needed.

Does anyone know of any papers/articles on code walking in Lisp?

I want something that will expand macrolets and where I can specify
what macros get expanded -- I don't always want a complete expansion.

I've implemented something that seems to work (see below).
The macro WALK-FORM expands everything, and WALK-FORM-PARTIALLY allows
you to specify which macros get expanded.

I'm hazy on special operators so it's likely that I've missed things.

I'd appreciate comments on the code (which is at the bottom of this
message).

First, some examples of its use:


(defmacro global-macro (x y)
  `(list ,x ,y))

(defmacro test-walk-form-partially (form)
  `(walk-form-partially (global-macro local-macro-1)
                        ,form))

(test-walk-form-partially (frog a b c))
=> (FROG A B C)

(test-walk-form-partially (global-macro a b))
=> (LIST A B)

(test-walk-form-partially (macrolet ((local-macro-1 (x y)
                                       `(list ,x ,y)))
                            (local-macro-1 a b)))
=> (LIST A B)

(walk-form (macrolet ((local-macro-1 (x y)
                        `(list ,x ,y)))
             7 8 9
             (local-macro-1 a b)))
=> (PROGN 7 8 9 (LIST A B))

(test-walk-form-partially (macrolet ((local-macro-1 (x y)
                                       `(list ,x ,y))
                                     (local-macro-2 (x y)
                                       `(list ,x ,y)))
                            (append (local-macro-1 a b)
                                    (local-macro-2 a b))))
=> (APPEND (LIST A B)
           (LOCAL-MACRO-2 A B))

(walk-form (macrolet ((local-macro-1 (x y)
                        `(list ,x ,y))
                      (local-macro-2 (x y)
                        `(list ,x ,y)))
             (append (local-macro-1 a b)
                     (local-macro-2 a b))))
=> (APPEND (LIST A B)
           (LIST A B))




The code:


;;;; ___________________________________________________________
;;;; ---- walk-form ----
;;;; ---- walk-form-partially ----
;;;; Walk a form expanding macro forms.
;;;; - WALK-FORM expands all macro forms.
;;;; - WALK-FORM-PARTIALLY gives you control over which macro
;;;;   forms are expanded, by allowing you to specify a list
;;;;   of macro names.
;;;; - MACROLET is always expanded.
;;;; - Symbol macros are not currently handled.

;;;; Thoughts on duplicate macro names:
;;;; - It's possible for several macros at different lexical
;;;;   locations to
;;;;   share the same name. WALK-FORM-PARTIALLY has no way of
;;;;   distinguishing between such macros.
;;;; - For macros defined by MACROLET during the walk, perhaps
;;;;   all uses of the macro should be expanded.
;;;;   - Then the result would always be equivalent to the input.
;;;;   - Also, this would get rid of the problem of duplicate
;;;;     macro names at distinct lexical locations.
;;;;   - But perhaps it's useful not to have to expand all such
;;;;     macros.

;;;; I'm not sure I like the use of (setf *operators-to-expand* ...),
;;;; but I don't know what else to do.
;;;; - will cause problems if there are nested calls of
;;;;   WALK-FORM-PARTIALLY
;;;; - unlikely for this to ever happen?

;;;; I don't know much about special operators, so I guess there are
;;;; problems here that I don't know about.

(defun never-expand? (operator)
  ;; Should there be more operators here?
  ;; - expanding (LAMBDA ...) gives (FUNCTION (LAMBDA ...))
  ;;   which would lead to infinite looping
  (member operator '(lambda)))

(defvar *operators-to-expand* nil
  "Either T, meaning expand all operators, or a list of operators
   to expand.")

(defun expand? (operator)
  (if (never-expand? operator)
      nil
    (or (eql *operators-to-expand* t)
        (member operator *operators-to-expand*))))

(defun progn-ify-or-first (forms)
  ;; so that expanded code doesn't contain forms like
  ;; (PROGN X) when simply X will do
  (cond ((null forms) nil)
        ((null (rest forms)) (first forms))
        (t `(progn ,@forms))))

(defmacro walk-form-1 (form &environment env)
  (if (atom form)
      `',form
    (let* ((operator (first form)))
      (cond ((eql operator 'macrolet)
             ;; define the macros and expand the body
             (destructuring-bind (bindings &body body) (rest form)
               `(macrolet ,bindings
                  (let ((expanded-body
                         (list ,@(loop for b in body
                                       collect `(walk-form-1 ,b)))))
                    (progn-ify-or-first expanded-body)))))
            ((and (macro-function operator env)
                  (expand? operator))
             `(walk-form-1 ,(macroexpand-1 form env)))
            (t
             `(list ,@(loop for f in form
                            collect `(walk-form-1 ,f))))))))

(defmacro walk-form (form)
  (setf *operators-to-expand* t)
  `(walk-form-1 ,form))

(defmacro walk-form-partially (operators form)
  (setf *operators-to-expand* operators)
  `(walk-form-1 ,form))
From: Fred Gilham
Subject: Re: Expand a macrolet form?
Date: 
Message-ID: <u7sn7f53kp.fsf@snapdragon.csl.sri.com>
> Does anyone know of any papers/articles on code walking in Lisp?

There's an article by Waters in LISP POINTERS that, from what I can
tell, is the canonical lisp code-walker article.

Turns out that that paper with a couple others is available at

    http://www.merl.com/papers/TR93-17/

--
Fred Gilham ······@csl.sri.com || "If I thought there was anything at
all in your arguments, I should have to be not only a theist, but an
Episcopalian to boot," he said, after one interchange, reckoning that
since Episcopalianism was, in his book, that than which nothing could
be worse, this was an effective reductio ad absurdum.
From: Simon Katz
Subject: Re: Expand a macrolet form?
Date: 
Message-ID: <a67n1v$c7r1k$1@ID-131024.news.dfncis.de>
> "Fred Gilham" <······@snapdragon.csl.sri.com> wrote
> in message ···················@snapdragon.csl.sri.com...
>
> > Does anyone know of any papers/articles on code walking in Lisp?
>
> There's an article by Waters in LISP POINTERS that, from what I can
> tell, is the canonical lisp code-walker article.
>
> Turns out that that paper with a couple others is available at
>
>     http://www.merl.com/papers/TR93-17/


Thanks -- that's clarified things for me.

The paper mentions these files:
   mexp-code.lisp (source code)
   mexp-test.lisp (test suite)
   mexp-doc.txt   (brief documentation)
and says that they are available by ftp from merl.com in the directory
/pub/lptrs. Despite trying repeatedly over the last few days, I can't
connect to the ftp server. (And even if I could, seeing as the paper
was written about ten years ago, I guess the files might no longer be
there.)

A Google search comes up with nothing other than the above URL.

So: Does anyone have copies of these files that they could send me, or
know of a place where I can get them?