From: Vladimir Zolotykh
Subject: AND, ENDP, NULL
Date: 
Message-ID: <3C623FBF.68E036AA@eurocom.od.ua>
Consider the following

(defmacro and2 (&rest args)
  (cond ((endp args) t)
        ((endp (cdr args)) (car args))
        (t
         `(if ,(car args)
              (and2 ,@(cdr args))
              nil))))

I wonder why on earth (macroexpand '(and2 a b c)) doesn't expand to

  (if a (if b c nil) nil)

BTW what are the advantages using ENDP rather than NULL ?

-- 
Vladimir Zolotykh                         ······@eurocom.od.ua

From: Fred Gilham
Subject: Re: AND, ENDP, NULL
Date: 
Message-ID: <u7u1sttfou.fsf@snapdragon.csl.sri.com>
Macroexpand will `repeatedly expand the form until it is no longer a
macro form'.

(IF A (AND2 B C) NIL)

which is what you get with (macroexpand '(and2 a b c)), is not a macro
form.  It *contains* a macro form.

If you want to expand all the macros in a particular form, you can
sometimes find a function that does that.  For example, in the PCL
code walker there's a function that does it:

* (walker:macroexpand-all  '(and2 a b c))             

(IF A (IF B C NIL) NIL)

-- 
Fred Gilham                                 ······@csl.sri.com
[My tutors] got bored sooner than I, and laid down a general rule
that all statements about languages had to be in a higher level
language.  I thereupon asked in what level of language that rule was
formulated.  I got a very bad report.    -- J. R. Lucas
From: Vladimir Zolotykh
Subject: Re: AND, ENDP, NULL
Date: 
Message-ID: <3C62C55A.B61A50D3@eurocom.od.ua>
Fred Gilham wrote:
> 
> which is what you get with (macroexpand '(and2 a b c)), is not a macro
> form.  It *contains* a macro form.

This is the point of my misunderstanding precisely. 
_Contains_ doesn't mean _is_.

I suppose the old C/C++/m4 experience played a joke on me.

-- 
Vladimir Zolotykh                         ······@eurocom.od.ua
From: Kent M Pitman
Subject: Re: AND, ENDP, NULL
Date: 
Message-ID: <sfwu1stioev.fsf@shell01.TheWorld.com>
Vladimir Zolotykh <······@eurocom.od.ua> writes:

> BTW what are the advantages using ENDP rather than NULL ?

Think of the difference between cutting lumber with and without safety
glasses.  It's saves time to not bother with safety.

Personally, I don't use ENDP.
From: Barry Margolin
Subject: Re: AND, ENDP, NULL
Date: 
Message-ID: <WCx88.5$R16.9991@burlma1-snr2>
In article <·················@eurocom.od.ua>,
Vladimir Zolotykh  <······@eurocom.od.ua> wrote:
>Consider the following
>
>(defmacro and2 (&rest args)
>  (cond ((endp args) t)
>        ((endp (cdr args)) (car args))
>        (t
>         `(if ,(car args)
>              (and2 ,@(cdr args))
>              nil))))
>
>I wonder why on earth (macroexpand '(and2 a b c)) doesn't expand to
>
>  (if a (if b c nil) nil)

Because macroexpand only expands the top-level expression, it doesn't dive
into the result of the expansion and expand its pieces.

-- 
Barry Margolin, ······@genuity.net
Genuity, Woburn, MA
*** DON'T SEND TECHNICAL QUESTIONS DIRECTLY TO ME, post them to newsgroups.
Please DON'T copy followups to me -- I'll assume it wasn't posted to the group.
From: Vladimir Zolotykh
Subject: Re: AND, ENDP, NULL
Date: 
Message-ID: <3C63F490.64E2F53F@eurocom.od.ua>
Here is the short summary.

The initial intention was to see macroexpansion as

  (if a (if x z nil) nil)

rather than

  (if a (and2 b x) nil)

Where AND2 is 

  (defmacro and2 (&rest args)
    (cond ((endp args) t)
          ((endp (cdr args)) (car args))
          (t
           `(if ,(car args)
                (and2 ,@(cdr args))
                nil))))

The following sketch (thank to Paul Foley) gives the basic idea how it
can be done.

(defun macroexpand-all (form &optional env)
  (let ((form (macroexpand form env)))
    (cond ((atom form) form)
          ((and (atom (first form)) (special-operator-p (first form)))
           (ecase (first form)
             ('if (list* 'if (mapcar #'(lambda (x)
                                         (macroexpand-all x env))
                                     (rest form))))

             ;; Handling of the other special operators could be added
             ;; here.
             ))
          (t                            ; it's an ordinary function
           (cond ((and (consp (first form)) (eq (car (first form)) 
                                                'lambda))
                  (list* (list* (caar form) (cadar form)
                                (mapcar #'(lambda (x) 
                                            (macroexpand-all x env))
                                        (cddar form)))
                         (mapcar #'(lambda (x) 
                                     (macroexpand-all x env))
                                 (cdr form))))
                 ((or (not (symbolp (first form))) 
                      (keywordp (first form)))
                  #| This is an error |#)
                 (t
                  (list* (first form) 
                         (mapcar #'(lambda (x) 
                                     (macroexpand-all x env)) 
                                 (rest form)))))))))

Now I could see:

  cl-user(26): (macroexpand-all '((lambda (x) (and2 a x z))))
  ((lambda (x) (if a (if x z nil) nil)))

-- 
Vladimir Zolotykh 

(format t ···@~{~A~^.~}" 'gsmith '(eurocom od ua))
From: Vladimir Zolotykh
Subject: Re: AND, ENDP, NULL
Date: 
Message-ID: <3C668AE4.4C01E44E@eurocom.od.ua>
BTW If I would write

(defmacro and2 (&rest args)
  (if (null args)
    t
    (labels ((expand (args)
	       (if (cdr args)
		 `(if ,(car args)
		    ,(expand (cdr args))
		    nil)
		 (car args))))
      (expand args))))

I wouldn't needed thing such as MACROEXPAND-ALL, but definitely would
knew subject less.

-- 
Vladimir Zolotykh
From: Kaz Kylheku
Subject: Re: AND, ENDP, NULL
Date: 
Message-ID: <S1y98.7456$A44.443550@news2.calgary.shaw.ca>
In article <·················@eurocom.od.ua>, Vladimir Zolotykh wrote:
>BTW If I would write
>
>(defmacro and2 (&rest args)
>  (if (null args)
>    t
>    (labels ((expand (args)
>	       (if (cdr args)
>		 `(if ,(car args)
>		    ,(expand (cdr args))
>		    nil)
>		 (car args))))
>      (expand args))))
>
>I wouldn't needed thing such as MACROEXPAND-ALL, but definitely would
>knew subject less.

Yes, but macros already do the work of recursive expansion for you,
so you'd be wasting your programming effort doing this in every macro.
It's easier to just write macroexpand-all. 

I think that macroexpand-all is a neat programming exercise, but doesn't
bring much to the table when it comes to debugging macros. In fact,
seeing less expansion is more useful, which is why there is macroexpand-1.
From: Thomas F. Burdick
Subject: Re: AND, ENDP, NULL
Date: 
Message-ID: <xcvbsex5dy5.fsf@conquest.OCF.Berkeley.EDU>
···@accton.shaw.ca (Kaz Kylheku) writes:

> In article <·················@eurocom.od.ua>, Vladimir Zolotykh wrote:
> >BTW If I would write
> >
> >(defmacro and2 (&rest args)
> >  (if (null args)
> >    t
> >    (labels ((expand (args)
> >	       (if (cdr args)
> >		 `(if ,(car args)
> >		    ,(expand (cdr args))
> >		    nil)
> >		 (car args))))
> >      (expand args))))
> >
> >I wouldn't needed thing such as MACROEXPAND-ALL, but definitely would
> >knew subject less.
> 
> Yes, but macros already do the work of recursive expansion for you,
> so you'd be wasting your programming effort doing this in every macro.
> It's easier to just write macroexpand-all. 
> 
> I think that macroexpand-all is a neat programming exercise, but doesn't
> bring much to the table when it comes to debugging macros. In fact,
> seeing less expansion is more useful, which is why there is macroexpand-1.

Even more fun, though, and more useful, is to write an expansion
browser.  Macro calls are differently colored than function calls; you
can click on the macro, and it'll get expanded.  That way, you can get
exactly the level of expansion you want :)

I might even dig out the old, broken garnet-based one I have, and see
if I can't fix it.  I think I had some conceptual problem with either
macros or part of Garnet when I wrote it, all I remember is that it
sometimes broke strangely.  It might be just the small project I need
to learn how to use (as a maintainer) common-lisp-controller, debian
packages, etc.

-- 
           /|_     .-----------------------.                        
         ,'  .\  / | No to Imperialist war |                        
     ,--'    _,'   | Wage class war!       |                        
    /       /      `-----------------------'                        
   (   -.  |                               
   |     ) |                               
  (`-.  '--.)                              
   `. )----'