From: Colin Benson
Subject: newbie macro question [PCL - destructuring parameter lists]
Date: 
Message-ID: <1192137463.792910.119110@22g2000hsm.googlegroups.com>
In chapter 8 of Practical Common Lisp, there are a couple of
definitions of a macro, do-primes. Here's the first one.

(defmacro do-primes (var-and-range &rest body)
  (let ((var (first var-and-range))
	(start (second var-and-range))
	(end (third var-and-range)))
    `(do ((,var (next-prime ,start) (next-prime (1+ ,var))))
	 ((> ,var ,end))
       ,@body)))

The text explains that all the gubbins to take the parameter list
apart is unnecessary because the parameter list is a "destructuring
parameter list". This allows a redefinition like this.

(defmacro do-primes ((var start end) &body body)
  `(do ((,var (next-prime ,start) (next-prime (1+ ,var))))
       ((> ,var ,end))
     ,@body))


Why are destructuring parameter lists different from any other
parameter list? For example, when I write

(defun hokey-kokey (in out all-about)
  (format t "~a" in)  (format t "~a" out)  (format t "~a" all-about))

I don't have to do any magic to get at the parameters. Is the
parameter list for hokey-kokey a destructuring parameter list?

Put this another way, I wrote this.

(defun hokey-kokey (in out all-about)
  (format t "~a" in)  (format t "~a" out)  (format t "~a" all-about))

(defmacro hokey-kokey1 (in out all-about)
  `(progn (format t "~a" ,in)
	  (format t "~a" ,out)
	  (format t "~a" ,all-about)))

Both definitions worked as I expected. When I write this

(defmacro do-primes (p from to)
  `(do ((,p (next-prime ,from) (next-prime (1+ ,to))))
       ((> ,p ,to))
     (format t "~d " ,p)))

Things don't work the way I think they should.

CL-USER> (do-primes n 0 19)
2
NIL

Where am I going wrong?

From: Ken Tilton
Subject: Re: newbie macro question [PCL - destructuring parameter lists]
Date: 
Message-ID: <ptxPi.2983$Yb2.943@newsfe12.lga>
Colin Benson wrote:
> In chapter 8 of Practical Common Lisp, there are a couple of
> definitions of a macro, do-primes. Here's the first one.
> 
> (defmacro do-primes (var-and-range &rest body)
>   (let ((var (first var-and-range))
> 	(start (second var-and-range))
> 	(end (third var-and-range)))
>     `(do ((,var (next-prime ,start) (next-prime (1+ ,var))))
> 	 ((> ,var ,end))
>        ,@body)))
> 
> The text explains that all the gubbins to take the parameter list
> apart is unnecessary because the parameter list is a "destructuring
> parameter list". This allows a redefinition like this.
> 
> (defmacro do-primes ((var start end) &body body)
>   `(do ((,var (next-prime ,start) (next-prime (1+ ,var))))
>        ((> ,var ,end))
>      ,@body))
> 
> 
> Why are destructuring parameter lists different from any other
> parameter list?  For example, when I write
> 
> (defun hokey-kokey (in out all-about)
>   (format t "~a" in)  (format t "~a" out)  (format t "~a" all-about))

Not fancy enough. Look up destructuring-bind, which I think has the same 
capabilities as macro destructuring. Nested lists, &rest and &key, yadda 
yadda.

> 
> I don't have to do any magic to get at the parameters. Is the
> parameter list for hokey-kokey a destructuring parameter list?
> 
> Put this another way, I wrote this.
> 
> (defun hokey-kokey (in out all-about)
>   (format t "~a" in)  (format t "~a" out)  (format t "~a" all-about))
> 
> (defmacro hokey-kokey1 (in out all-about)
>   `(progn (format t "~a" ,in)
> 	  (format t "~a" ,out)
> 	  (format t "~a" ,all-about)))
> 
> Both definitions worked as I expected. When I write this
> 
> (defmacro do-primes (p from to)
>   `(do ((,p (next-prime ,from) (next-prime (1+ ,to))))
>        ((> ,p ,to))
>      (format t "~d " ,p)))
> 
> Things don't work the way I think they should.
> 
> CL-USER> (do-primes n 0 19)
> 2
> NIL
> 
> Where am I going wrong?
> 

Just a simple bug in your version, nothing to do with macros.

kt

-- 
http://www.theoryyalgebra.com/

"Mother always told me, if you tell a lie,
always rehearse it. If it don't sound good
to you, it won't sound good to no one else."
                          - Satchel Paige
From: Barry Margolin
Subject: Re: newbie macro question [PCL - destructuring parameter lists]
Date: 
Message-ID: <barmar-417C0E.22541111102007@comcast.dca.giganews.com>
In article <························@22g2000hsm.googlegroups.com>,
 Colin Benson <·········@gmail.com> wrote:

> Why are destructuring parameter lists different from any other
> parameter list? For example, when I write
> 
> (defun hokey-kokey (in out all-about)
>   (format t "~a" in)  (format t "~a" out)  (format t "~a" all-about))
> 
> I don't have to do any magic to get at the parameters. Is the
> parameter list for hokey-kokey a destructuring parameter list?

Destructuring parameter lists are recursive: you can put lists in place 
of variables, and it will automatically dive down into the structure of 
the parameter.

You can't write:

(defun hokey-kokey ((in out) all-about) ...)

but you *can* write

(defmacro with-foo ((var binding) &body body) ...)

-- 
Barry Margolin, ······@alum.mit.edu
Arlington, MA
*** PLEASE post questions in newsgroups, not directly to me ***
*** PLEASE don't copy me on replies, I'll read them in the group ***
From: Rainer Joswig
Subject: Re: newbie macro question [PCL - destructuring parameter lists]
Date: 
Message-ID: <joswig-EB3567.00152412102007@news-europe.giganews.com>
In article <························@22g2000hsm.googlegroups.com>,
 Colin Benson <·········@gmail.com> wrote:

> In chapter 8 of Practical Common Lisp, there are a couple of
> definitions of a macro, do-primes. Here's the first one.
> 
> (defmacro do-primes (var-and-range &rest body)
>   (let ((var (first var-and-range))
> 	(start (second var-and-range))
> 	(end (third var-and-range)))
>     `(do ((,var (next-prime ,start) (next-prime (1+ ,var))))
> 	 ((> ,var ,end))
>        ,@body)))
> 
> The text explains that all the gubbins to take the parameter list
> apart is unnecessary because the parameter list is a "destructuring
> parameter list". This allows a redefinition like this.
> 
> (defmacro do-primes ((var start end) &body body)
>   `(do ((,var (next-prime ,start) (next-prime (1+ ,var))))
>        ((> ,var ,end))
>      ,@body))
> 
> 
> Why are destructuring parameter lists different from any other
> parameter list? For example, when I write
> 
> (defun hokey-kokey (in out all-about)
>   (format t "~a" in)  (format t "~a" out)  (format t "~a" all-about))
> 
> I don't have to do any magic to get at the parameters. Is the
> parameter list for hokey-kokey a destructuring parameter list?

No. Destructuring Parameter Lists are available for
macros, but not for functions.

Remember a function call looks like:

   (f1 foo .. baz)

A macro expression can look like this:

   (with-something (foo bar) baz))

the destructuring definition would be

   (defmacro with-something ((arg1 arg2) arg3)
     ...)

So you can use nested lists in the definition of
a macro and the macro usage will be automatically
destructured.

You can do this also inside functions with
DESTRUCTURING-BIND.

   (destructuring-bind ((arg1 arg2) arg3)
                  '((foo bar) baz)
     (print arg1)
     (print arg2)
     (print arg3)
     (values))

Which let's us rewrite above macro:

  (defmacro with-something (&rest args)
     (destructuring-bind ((arg1 arg2) arg3)  args
       ...))

Most of the time the former is better, since it
is shorter and the parameter list shows
the details.

> 
> Put this another way, I wrote this.
> 
> (defun hokey-kokey (in out all-about)
>   (format t "~a" in)  (format t "~a" out)  (format t "~a" all-about))
> 
> (defmacro hokey-kokey1 (in out all-about)
>   `(progn (format t "~a" ,in)
> 	  (format t "~a" ,out)
> 	  (format t "~a" ,all-about)))
> 
> Both definitions worked as I expected. When I write this
> 
> (defmacro do-primes (p from to)
>   `(do ((,p (next-prime ,from) (next-prime (1+ ,to))))
>        ((> ,p ,to))
>      (format t "~d " ,p)))
> 
> Things don't work the way I think they should.
> 
> CL-USER> (do-primes n 0 19)

Do a MACROEXPAND to see what the code looks like.

> 2
> NIL
> 
> Where am I going wrong?
From: Alan Crowe
Subject: Re: newbie macro question [PCL - destructuring parameter lists]
Date: 
Message-ID: <868x687z2f.fsf@cawtech.freeserve.co.uk>
Colin Benson <·········@gmail.com> asks:
> 
> Why are destructuring parameter lists different from any
> other parameter list?

Macros and functions differ greatly.

Looking in the source code, at the call site, there is a
sense in which both macros and functions involve two rounds
of evaluation, but differently organised.

Look at this macro

CL-USER> (defmacro foo ((a b c)(x y z))
           (cons 'progn 
                 (list (list a x)
                       (list b y)
                       (list c z))))
FOO

Here is a sample call. 

CL-USER> (foo (print (lambda(x)(print x)(print x)) exp)
              (1 2 3))

1 
2 
2 

20.085537

Notice that both arguments are data not code
in the sense that neither list is a valid Common Lisp form.

(print (lambda(x)(print x)(print x)) exp)

has the wrong argument count
while

(1 2 3)

has a number where it needs a function name.

Notice the macro definition and the call site are sufficient
to allow checking that the destructuring is valid.  There
are two rounds of evaluation. At macroexpansion time, the
arguments, which are data, are processed to produce Common
Lisp.  At runtime the Common Lisp is executed to produce
more data.

Imagine if functions had destructuring lambda lists.

(defun bar ((a b c)(x y z))
  ...)

Now look at the call site

(bar (f x1 y1) (g y1 y2))

Does this set up the bindings 
a=f, b=x1, c=y1, x=g, y=y1, z=y2?

No, there is a weak sense in which function calls also
involve two rounds of evaluation. The arguments at the call
site must be valid Common Lisp. This restriction does not
apply to macros but it is essential for functions because
the arguments are executed at run time to obtain the data
that is feed to the function and processed to obtain the
data that results from the function call.

So (f x1 y1) is not matched to (a b c). It is the result of
the calculation of (f x1 y1) that is matched to (a b c).
It is no good to attempt to statically check the program by
comparing the call site with the destructuring argument
list. Validity depends on the definition of f and typically
on much more such that it can only be checked at run time.

The parameter lists of macros work very differently to the
parameter lists of functions. Should the parameter lists of
macros destructure? Should the parameter lists of functions
destructure? These are two separate questions, and I have no
expectation that the answers should be the same. Without
such an expectation the question of why they are different
does not arise.

To answer the second question, if the parameter lists of
functions are to destructure, I think you want more than one
pattern, with the body of code chosen according to which one
matches. So one is taken down a different language design
path, unrelated to macros.

Alan Crowe
Edinburgh
Scotland
From: Colin Benson
Subject: Re: newbie macro question [PCL - destructuring parameter lists]
Date: 
Message-ID: <1192619994.280693.300380@v29g2000prd.googlegroups.com>
Thank you Alan. Also Rainier, Ken and Barry. As Mr T pointed out, the
root cause of my confusion was a brain cramp in my
macro. Destructuring paremeter lists were a red-herring. However, I've
learned a lot more about them thanks to your answers.

On an only slightly related note, is there anything that might
resemble a Lisp user group in Edinburgh?

c


On Oct 12, 11:22 pm, Alan Crowe <····@cawtech.freeserve.co.uk> wrote:
...
>
> Alan Crowe
> Edinburgh
> Scotland
From: Alan Crowe
Subject: Re: newbie macro question [PCL - destructuring parameter lists]
Date: 
Message-ID: <86bqaxy7jv.fsf@cawtech.freeserve.co.uk>
Colin Benson <·········@gmail.com> writes:

> On an only slightly related note, is there anything that might
> resemble a Lisp user group in Edinburgh?
> 

Not at the moment. My plans are:

1)Exorcise the spirit of Cthulhu from Tim Bradshaw.

  Not that I have anything against elder gods, it is just
  that using his facial tentacles for typing on his lap top
  keeps getting us thrown out of coffee shops before I can
  finish my chocolate cake.

2)Build my own Lispniks.  

  Make the bodies on my lathe and code up the brains using
  Common Lisp and Cells.

Alan Crowe
Edinburgh
Scotland