From: Michael J. Forster
Subject: Nested &REST parameter vs. single named parameter
Date: 
Message-ID: <1131823755.162812.17080@g14g2000cwa.googlegroups.com>
Hi,

As I understand it, I have two choices when defining a function to
accept an arbitrary number of inputs: a single named parameter
that takes an argument list, or a &REST parameter taking an
arbitrary number of arguments.  Christopher C. Stacy said as
much in an earlier thread [1]:

    Your function could either take &REST ARGS, or require the caller
    to do the consing and your function takes a single LIST-OF-ARGS.
    In any case, once you have consed up a list of args that need to
    be applied to a function, you will of course want to use APPLY.

In another thread [2], Steven E. Harris suggested that this might be
just a matter of style, but that he found the choice of idiom
difficult.  In that same thread, Barry Margolin responded:

   It's just a convenience feature that allows for terser
   function calls.  There's no semantic difference between:

   (defun fun1 (&rest args) ...)
   (fun1 ...)

   and

   (defun fun2 (args) ...)
   (fun2 (list ...))

Aside from the interaction of &REST parameters with &KEY
parameters, this choice does seem to be a matter of taste.
However, to me, the difference is further blurred when
comparing the implementations of WITH-GENSYMS by Paul
Graham [3]

   (defmacro with-gensyms (syms &body body)
     `(let ,(mapcar #'(lambda (s)
                        `(,s (gensym)))
                    syms)
        ,@body))

and Peter Seibel [4]

   (defmacro with-gensysms ((&rest names) &body body)
     `(let ,(loop for n in names collect `(,n (gensysm)))
        ,@body))

Both require me to pass the the arguments in a list

    (with-gensyms (foo bar baz)
      ...)

Is there any reason to write ((&rest names) ...) instead of
(syms ...) in this example?

Thanks in advance,

Mike

--
Michael J. Forster
Shared Logic Inc.

From: Michael J. Forster
Subject: Re: Nested &REST parameter vs. single named parameter
Date: 
Message-ID: <1131823954.363635.198170@g49g2000cwa.googlegroups.com>
Oops!   Missed pasting the references.  Sorry.

[1] "&rest parameters vs. multiple arguments?"
http://groups.google.ca/group/comp.lang.lisp/browse_frm/thread/419217a0ff4d8b52/cd12c3c6eb3fd47c?

[2] "macros, &rest parameters, mulitple evaluation, and forwarding"
http://groups.google.ca/group/comp.lang.lisp/browse_frm/thread/e2ac67983a45b447/f2ef8c49f742c5c8?

[3] Ansi Common Lisp, Paul Graham, p. 170.

[4] Practical Common Lisp, Peter Seibel, p. 101.
From: Bill Atkins
Subject: Re: Nested &REST parameter vs. single named parameter
Date: 
Message-ID: <1131828477.134398.110980@o13g2000cwo.googlegroups.com>
I would agree that this difference is mostly about style.  Peter
Seibel's version makes it more explicit that the macro is taking a list
of names, while Graham's syms could take any value.  So Seibel's
version makes it immediately clear that

  (with-gensyms x
     ...)

is not legal.  Graham's version will accept such an argument and then
fail during macroexpansion because syms is not a list.  I prefer
Peter's.

HTH,
Bill
From: Michael J. Forster
Subject: Re: Nested &REST parameter vs. single named parameter
Date: 
Message-ID: <1131837992.306484.12440@g49g2000cwa.googlegroups.com>
Thanks Bill!

Yes, that does help.  I had wondered if that's what it came down
to, but, being a newb, I didn't want to assume to much.

Mike

-- 
Michael J. Forster
Shared Logic Inc.
From: Jeff M.
Subject: Re: Nested &REST parameter vs. single named parameter
Date: 
Message-ID: <1131843465.963594.264250@g43g2000cwa.googlegroups.com>
I follow in Peter's camp, for two reasons:

1. It is more explicit
2. There are more options

You can use other parameter keywords that you couldn't use otherwise.
For example, in my 2D game engine, I have a macro that accepts a body
and keywords:

(defmacro with-open-display ((&key (width 640)
                                   (height 480)
                                   (fullscreen t))
                               &body body)
  ;...
)

This would be very similar to the with-open-file macro. However, you
may want to consider using Paul's version if you are creating a macro
that will get called from within other macros with data. Having to use
,@ to expand a list so that it conforms to what a macro wants can be
very obnoxious (in my opinion).

Jeff M.
From: Bill Atkins
Subject: Re: Nested &REST parameter vs. single named parameter
Date: 
Message-ID: <1131856940.521607.200490@g14g2000cwa.googlegroups.com>
Hmm, why would you have to use ,@?  If you're writing a macro that will
expand into a with-gensyms, you can either:

 1) if your variable is a symbol:

      (with-gensyms (,var)
         ...)

 2) if your variable is a list:

      (with-gensyms ,var
        ...)

Using ,@var would probably cause an error, since e.g. if var is (1 2
3), then (with-gensyms ,@var ...) becomes:

      (with-gensyms 1 2 3
         ....)

which is not the right thing at all.  Or maybe I misunderstood. :)
From: Jeff M.
Subject: Re: Nested &REST parameter vs. single named parameter
Date: 
Message-ID: <1131869260.542599.45920@g43g2000cwa.googlegroups.com>
Hmm, as I go back to my old code where this was a problem, my problem
was actually a little bit more complex (so, my example was seriously
flawed).

It turns out it wasn't in a macro, but in a function and debating when
and when not to use &rest -- in almost the same context as the OP.

So, please move along, nothing to see here, but my comments on the use
of keywords in macros stands.. :-)

Jeff M.
From: Michael J. Forster
Subject: Re: Nested &REST parameter vs. single named parameter
Date: 
Message-ID: <1131864398.485699.272070@z14g2000cwz.googlegroups.com>
In my case, I've written a macro similar to CL-HTTP's
bind-query-values, but for use with (Portable) AllegroServe.
My original question stemmed from wanting to mimic the
parameter order of the aserve function

  (request-query-value key request &key uri post external-format test)

which is part of the expansion.  My macro takes a list of
'queries' where the aserve function takes a 'key'.

  (defmacro request-query-values-bind (((&rest queries)
             request
             &key (uri t)
             (post t)
             (external-format *default-aserve-external-format*)
             test)
          &body body)
  ;; ...
  )

An example call might be as follows:

  (request-query-values-bind (
       (type
        search
        (order-by string "username")
        (batch-number integer 0))
      req)
   (with-http-response (req ent)
     (with-http-body (req ent)
       (html
         (:html
           (:body
             (:princ-safe "type: ") (:princ-safe type) (:br)
             (:princ-safe "search: ") (:princ-safe search) (:br)
             (:princ-safe "order-by: ") (:princ-safe order-by) (:br)
             (:princ-safe "batch-number: ") (:princ-safe
batch-number))))))))


Mike

--
Michael J. Forster
Shared Logic Inc.
From: Kalle Olavi Niemitalo
Subject: Re: Nested &REST parameter vs. single named parameter
Date: 
Message-ID: <87oe4p5wvn.fsf@Astalo.kon.iki.fi>
"Bill Atkins" <·········@gmail.com> writes:

> Peter Seibel's version makes it more explicit that the macro is
> taking a list of names, while Graham's syms could take any value.

I suppose, in principle, an editor could check the parameter list
of a macro as soon as you have typed its name (and a space), and
insert a template for the corresponding arguments; then the
((&rest names) &body body) version could bring up an empty pair
of parentheses.

I don't know whether any editors do this, and if they do, whether
it is actually useful or just annoying.

On a second thought, there is plenty of macro syntax that cannot
be expressed with mere lambda lists, e.g. in LOOP.  So it might
be even better to have declarations that describe the possible
syntaxes and their corresponding templates for each macro (and
perhaps even how to indent them).  I'd be interested in knowing
if such things have been implemented somewhere.  (To my
intoxicated mind, this seems analogous to option completion
within backquoted or otherwise nested Unix commands.)
From: nepheles
Subject: Re: Nested &REST parameter vs. single named parameter
Date: 
Message-ID: <1131905371.294751.230290@g14g2000cwa.googlegroups.com>
Michael J. Forster wrote:
> Hi,
> ...
> In another thread [2], Steven E. Harris suggested that this might be
> just a matter of style, but that he found the choice of idiom
> difficult.  In that same thread, Barry Margolin responded:
>
>    It's just a convenience feature that allows for terser
>    function calls.  There's no semantic difference between:
>
>    (defun fun1 (&rest args) ...)
>    (fun1 ...)
>
>    and
>
>    (defun fun2 (args) ...)
>    (fun2 (list ...))

Except in the case that fun1 destructively modifies args, and is
running in a Lisp implementation that doesn't provide freshly-consed
lists in &rest parameters (Zetalisp springs to mind).
From: Peter Seibel
Subject: Re: Nested &REST parameter vs. single named parameter
Date: 
Message-ID: <m2slu01m9q.fsf@gigamonkeys.com>
"Michael J. Forster" <····@sharedlogic.ca> writes:

> Aside from the interaction of &REST parameters with &KEY
> parameters, this choice does seem to be a matter of taste.
> However, to me, the difference is further blurred when
> comparing the implementations of WITH-GENSYMS by Paul
> Graham [3]
>
>    (defmacro with-gensyms (syms &body body)
>      `(let ,(mapcar #'(lambda (s)
>                         `(,s (gensym)))
>                     syms)
>         ,@body))
>
> and Peter Seibel [4]
>
>    (defmacro with-gensysms ((&rest names) &body body)
>      `(let ,(loop for n in names collect `(,n (gensysm)))
>         ,@body))
>
> Both require me to pass the the arguments in a list
>
>     (with-gensyms (foo bar baz)
>       ...)
>
> Is there any reason to write ((&rest names) ...) instead of
> (syms ...) in this example?

I use ((&rest names) ...) because that gives me a bit of error
checking for free--if you try to write:

  (with-gensyms 10 (stuff))

the compiler will complain if you use my version because 10 is not a
list.

-Peter

-- 
Peter Seibel           * ·····@gigamonkeys.com
Gigamonkeys Consulting * http://www.gigamonkeys.com/
Practical Common Lisp  * http://www.gigamonkeys.com/book/
From: Michael J. Forster
Subject: Re: Nested &REST parameter vs. single named parameter
Date: 
Message-ID: <1131906014.563834.215760@g49g2000cwa.googlegroups.com>
Peter Seibel wrote:
> I use ((&rest names) ...) because that gives me a bit of error
> checking for free--if you try to write:
>
>   (with-gensyms 10 (stuff))
>
> the compiler will complain if you use my version because 10 is not a
> list.

Which is why I have decided now to use '(&rest queries)' instead of
'queries' in my macro.  Thanks for the insight.

And thanks for PCL!  It has been invaluable to us as we migrate our
development efforts to Lisp.

-Mike

--
Michael J. Forster
Shared Logic Inc.
From: Edi Weitz
Subject: Re: Nested &REST parameter vs. single named parameter
Date: 
Message-ID: <u1x1kfmcd.fsf@agharta.de>
On Sun, 13 Nov 2005 17:38:10 GMT, Peter Seibel <·····@gigamonkeys.com> wrote:

>   (with-gensyms ...

BTW, I think one should use WITH-UNIQUE-NAMES instead.  See the end of
this page

  <http://www.cliki.net/WITH-UNIQUE-NAMES>

for my rationale.

Cheers,
Edi.

-- 

Lisp is not dead, it just smells funny.

Real email: (replace (subseq ·········@agharta.de" 5) "edi")
From: Cameron MacKinnon
Subject: Re: Nested &REST parameter vs. single named parameter
Date: 
Message-ID: <lMydnfXgTYanEereRVn-hw@rogers.com>
Edi Weitz wrote:
> BTW, I think one should use WITH-UNIQUE-NAMES instead.  See the end of
> this page
> 
>   <http://www.cliki.net/WITH-UNIQUE-NAMES>

Just as an aside, most of the links on that page (pointing into an 
Xanalys copy of the CLHS) are broken.
From: Bulent Murtezaoglu
Subject: Re: Nested &REST parameter vs. single named parameter
Date: 
Message-ID: <87acg8l4nt.fsf@p4.internal>
>>>>> "CM" == Cameron MacKinnon <··········@clearspot.net> writes:
[...]
    CM> Just as an aside, most of the links on that page (pointing
    CM> into an Xanalys copy of the CLHS) are broken. [...]

I think I fixed most a minute agp.  I may have missed one or two.  
Volunteers?

cheers,

BM
From: Damien Kick
Subject: Re: Nested &REST parameter vs. single named parameter
Date: 
Message-ID: <dkixk-1411051721120001@113.0.0.10.in-addr.arpa>
In article <·············@agharta.de>, ········@agharta.de wrote:

> On Sun, 13 Nov 2005 17:38:10 GMT, Peter Seibel <·····@gigamonkeys.com> wrote:
> 
> >   (with-gensyms ...
> 
> BTW, I think one should use WITH-UNIQUE-NAMES instead.  See the end of
> this page
> 
>   <http://www.cliki.net/WITH-UNIQUE-NAMES>
> 
> for my rationale.

<laugh> And I was just wondering why WITH-GENSYSM wasn't <pause>
WITH-UNIQUE-NAMES.
From: Damien Kick
Subject: Re: Nested &REST parameter vs. single named parameter
Date: 
Message-ID: <dkixk-1411051716520001@113.0.0.10.in-addr.arpa>
In article <··············@gigamonkeys.com>, Peter Seibel
<·····@gigamonkeys.com> wrote:

> "Michael J. Forster" <····@sharedlogic.ca> writes:
> 
> >
> > [...] and Peter Seibel [4]
> >
> >    (defmacro with-gensysms ((&rest names) &body body)
> >      `(let ,(loop for n in names collect `(,n (gensysm)))
> >         ,@body))
> >
> 
> I use ((&rest names) ...) because that gives me a bit of error
> checking for free--if you try to write:
> 
>   (with-gensyms 10 (stuff))
> 
> the compiler will complain if you use my version because 10 is not a
> list.

I've been wondering more and more lately why with-gensyms isn't defined as
follows:

(defmacro with-gensyms ((&rest names) &body forms)
  `(let ,(loop for n in names
               collect `(,n (gensym ,(concatenate 'string
                                                  (symbol-name n)
                                                  "/"))))
    ,@forms))

So that the symbol has a bit of the original name in it to help make the
macroexpansions a bit more readable.
From: Cameron MacKinnon
Subject: Re: Nested &REST parameter vs. single named parameter
Date: 
Message-ID: <6Z6dnWc_IogFgeTeRVn-vg@rogers.com>
Damien Kick wrote:
> I've been wondering more and more lately why with-gensyms isn't defined as
> follows:

...

> So that the symbol has a bit of the original name in it to help make the
> macroexpansions a bit more readable.

Seems reasonable, but what if there's five levels of macroexpansion 
going on and each level uses gensyms? Those gensyms are going to get 
pretty long...
From: Sam Steingold
Subject: Re: Nested &REST parameter vs. single named parameter
Date: 
Message-ID: <uzmo6vm4a.fsf@gnu.org>
> * Damien Kick <·····@rneguyvax.arg> [2005-11-14 23:16:56 +0000]:
>
> I've been wondering more and more lately why with-gensyms isn't defined as
> follows:
>
> (defmacro with-gensyms ((&rest names) &body forms)
>   `(let ,(loop for n in names
>                collect `(,n (gensym ,(concatenate 'string
>                                                   (symbol-name n)
>                                                   "/"))))
>     ,@forms))
>
> So that the symbol has a bit of the original name in it to help make
> the macroexpansions a bit more readable.

it is - in CLOCC/PORT/ext.lisp

(defmacro with-gensyms ((title &rest names) &body body)
  "Bind symbols in NAMES to gensyms.  TITLE is a string - `gensym' prefix.
Inspired by Paul Graham, <On Lisp>, p. 145."
  `(let (,@(mapcar (lambda (sy)
                     `(,sy (gensym ,(concatenate 'string title
                                                 (symbol-name sy) "-"))))
                   names))
     ,@body))


-- 
Sam Steingold (http://www.podval.org/~sds) running w2k
http://www.honestreporting.com http://truepeace.org
http://ffii.org/ http://www.jihadwatch.org/ http://www.camera.org
Can I do it in Lisp, or would you rather wait an extra couple of months?
From: Thomas F. Burdick
Subject: Re: Nested &REST parameter vs. single named parameter
Date: 
Message-ID: <xcvek5ivwph.fsf@conquest.OCF.Berkeley.EDU>
·····@earthlink.net (Damien Kick) writes:

> I've been wondering more and more lately why with-gensyms isn't defined as
> follows:
> 
> (defmacro with-gensyms ((&rest names) &body forms)
>   `(let ,(loop for n in names
>                collect `(,n (gensym ,(concatenate 'string
>                                                   (symbol-name n)
>                                                   "/"))))
>     ,@forms))

That's quite similar to how I define it.  I think a lot of lispers
have the original name in their gensym.

-- 
           /|_     .-----------------------.                        
         ,'  .\  / | Free Mumia Abu-Jamal! |
     ,--'    _,'   | Abolish the racist    |
    /       /      | death penalty!        |
   (   -.  |       `-----------------------'
   |     ) |                               
  (`-.  '--.)                              
   `. )----'                               
From: Peter Seibel
Subject: Re: Nested &REST parameter vs. single named parameter
Date: 
Message-ID: <m2zmo595xf.fsf@gigamonkeys.com>
·····@earthlink.net (Damien Kick) writes:

> In article <··············@gigamonkeys.com>, Peter Seibel
> <·····@gigamonkeys.com> wrote:
>
>> "Michael J. Forster" <····@sharedlogic.ca> writes:
>> 
>> >
>> > [...] and Peter Seibel [4]
>> >
>> >    (defmacro with-gensysms ((&rest names) &body body)
>> >      `(let ,(loop for n in names collect `(,n (gensysm)))
>> >         ,@body))
>> >
>> 
>> I use ((&rest names) ...) because that gives me a bit of error
>> checking for free--if you try to write:
>> 
>>   (with-gensyms 10 (stuff))
>> 
>> the compiler will complain if you use my version because 10 is not a
>> list.
>
> I've been wondering more and more lately why with-gensyms isn't defined as
> follows:
>
> (defmacro with-gensyms ((&rest names) &body forms)
>   `(let ,(loop for n in names
>                collect `(,n (gensym ,(concatenate 'string
>                                                   (symbol-name n)
>                                                   "/"))))
>     ,@forms))
>
> So that the symbol has a bit of the original name in it to help make the
> macroexpansions a bit more readable.

FWIW, here's the version of WITH-GENSYMS from my macro-utilities library.

  (defmacro with-gensyms ((&rest names) &body body)
    `(let ,(loop for n in names collect `(,n (make-symbol ,(string n))))
       ,@body))

I think I used a different version in my book because I didn't want to
have to bother explaining the difference between MAKE-SYMBOL and
GENSYM.

-Peter

-- 
Peter Seibel           * ·····@gigamonkeys.com
Gigamonkeys Consulting * http://www.gigamonkeys.com/
Practical Common Lisp  * http://www.gigamonkeys.com/book/
From: Damien Kick
Subject: Re: Nested &REST parameter vs. single named parameter
Date: 
Message-ID: <dkixk-1711052037030001@10.0.1.2>
In article <··············@gigamonkeys.com>, Peter Seibel
<·····@gigamonkeys.com> wrote:

> 
> FWIW, here's the version of WITH-GENSYMS from my macro-utilities library.
> 
>   (defmacro with-gensyms ((&rest names) &body body)
>     `(let ,(loop for n in names collect `(,n (make-symbol ,(string n))))
>        ,@body))
> 
> I think I used a different version in my book because I didn't want to
> have to bother explaining the difference between MAKE-SYMBOL and
> GENSYM.

I had thought at some point that using make-symbol should be as good as
gensym but then I started to wonder about if one had nested
macroexpansions that used the same name.  Each make-symbol would create a
unique uninterned symbol but with the same printed representation.  This
might not be the most concise example:

Damien-Kicks-Computer:~/tmp dkick$ cat duff.lisp
(in-package #:pg-user)

(eval-when (:compile-toplevel :load-toplevel :execute)

  (defmacro my-with-gensyms ((&rest names) &body forms)
    `(let ,(loop for n in names
                 collect `(,n (gensym ,(concatenate 'string
                                                    (symbol-name n)
                                                    "/"))))
      ,@forms))
  
  (defmacro duff (&body forms)
    (my-with-gensyms (x y z)
      `(let ((,x 13)
             (,y 69)
             (,z 71))
        (progn
          (list ,x ,y ,z)
          (list ,@forms)))))

  (defmacro fudd (&body forms)
    (my-with-gensyms (x y z)
      `(duff ',x ',y ',z ,@forms))))

(eval-when (:compile-toplevel :load-toplevel :execute) 

  (defmacro my-with-make-symbols ((&rest names) &body forms)
    `(let ,(loop for n in names
                 collect `(,n (make-symbol ,(symbol-name n))))
      ,@forms))
  
  (defmacro duff* (&body forms)
    (my-with-make-symbols (x y z)
      `(let ((,x 13)
             (,y 69)
             (,z 71))
        (progn
          (list ,x ,y ,z)
          (list ,@forms)))))

  (defmacro fudd* (&body forms)
    (my-with-make-symbols (x y z)
      `(duff* ',x ',y ',z ,@forms))))
Damien-Kicks-Computer:~/tmp dkick$ 

And then from the REPL

CL-USER> (in-package #:pg-user)
#<Package "PLAYGROUND-USER">
;;;; Compile file /Users/dkick/tmp/duff.lisp ...
PG-USER> (as pprint
             (as macroexpand-1
                 '(duff 1 2 3)))

(LET ((#:X/118 13) (#:Y/119 69) (#:Z/120 71))
  (PROGN (LIST #:X/118 #:Y/119 #:Z/120) (LIST 1 2 3)))

; No value
PG-USER> (as pprint
             (as macroexpand-1
                 '(fudd 1 2 3)))

(DUFF '#:X/121 '#:Y/122 '#:Z/123 1 2 3)

; No value
PG-USER> (as pprint
             (as macroexpand
                 '(fudd 1 2 3)))

(LET ((#:X/127 13) (#:Y/128 69) (#:Z/129 71))
  (PROGN (LIST #:X/127 #:Y/128 #:Z/129)
         (LIST '#:X/124 '#:Y/125 '#:Z/126 1 2 3)))
; No value
PG-USER> (as pprint
             (as macroexpand-1
                 '(duff* 1 2 3)))

(LET ((#:X 13) (#:Y 69) (#:Z 71)) (PROGN (LIST #:X #:Y #:Z) (LIST 1 2 3)))
; No value
PG-USER> (as pprint
             (as macroexpand-1
                 '(fudd* 1 2 3)))

(DUFF* '#:X '#:Y '#:Z 1 2 3)

; No value
PG-USER> (as pprint
             (as macroexpand
                 '(fudd* 1 2 3)))

(LET ((#:X 13) (#:Y 69) (#:Z 71))
  (PROGN (LIST #:X #:Y #:Z) (LIST '#:X '#:Y '#:Z 1 2 3)))

; No value
PG-USER> 

Does anyone else see this as a problem with using make-symbol?
From: Kaz Kylheku
Subject: Re: Nested &REST parameter vs. single named parameter
Date: 
Message-ID: <1132077309.120933.11200@g14g2000cwa.googlegroups.com>
Michael J. Forster wrote:
> Hi,
>
> As I understand it, I have two choices when defining a function to
> accept an arbitrary number of inputs: a single named parameter
> that takes an argument list, or a &REST parameter taking an
> arbitrary number of arguments.  Christopher C. Stacy said as
> much in an earlier thread [1]:
>
>     Your function could either take &REST ARGS, or require the caller
>     to do the consing and your function takes a single LIST-OF-ARGS.
>     In any case, once you have consed up a list of args that need to
>     be applied to a function, you will of course want to use APPLY.

When you use &rest, and pass down the list to another function using
apply, implementations can optimize that so that no intermediate list
is actually consed up. The arguments can be passed on the stack.

  (defun wrapper (&rest args)
     (apply #'wrapped-function args)) ;; list can be optimized away

This optimization is highly unlikely to happen if you have an ordinary
parameter that takes a list expression.   &rest is a more abstract way
of passing a variable number of arguments, because it expresses the
idea specifically and directly. Using lists achieves the same semantics
in a Turing equivalence sense, but it doesn't quite express the same
idea. In spite of all pretenses to the contrary, the elements of a list
are not in fact function arguments, but the members of an object that
was constructed to emulate arguments.

On the other hand, for a reason related to the freedom of the
underlying mechanism, there may be (and usually are) limitations on the
lengths of a &rest argument list, which are overcome if you use an
actual list.

So there are technical reasons to choose one or the other: &rest gives
you interface simplicitly (in situations when you don't already have a
list!) and optimization. A list argument removes some limitations and
gives you additional flexibility, like being able to pass something
other than a list!

A list parameter can be the specializable parameter of a method, so
that

  (func 42 (list 1 2 3))

can actually be a generic function call, which goes to:

  (defmethod ((x number) (y list)) ...)

and you can still have:

  (func 42 "foo")

which goes to another method.

> Is there any reason to write ((&rest names) ...) instead of
> (syms ...) in this example?

((&rest syms) ...) can match only a list in the first position

(syms ...) can match any object in the first position; anything at all
can be bound to syms, which you have to typecheck yourself, or else let
it fail deeper in your macro.

And of course ((&rest syms) ...) is just a special case of ((args ...
&rest syms) ...)

There is value in having that initial sequence of required and optional
parameters destructured for you.