From: Sam Steingold
Subject: empty lists in destructuring
Date: 
Message-ID: <ufz9r1v9l.fsf@gnu.org>
is it OK for a destructuring lambda list to have NIL elements?
(i.e., empty subtrees)

E.g., what should
      (macrolet ((%m (()) :good)) (%m ()))
and
      (macrolet ((%m (()) :good)) (%m 10))
return?

A.  NIL cannot be bound so both should signal an error (CLISP)

B.  () matches (), so the first form returns :GOOD, while 10 does not
    match (), so the second form signals an error (LWW)

C.  () is an equivalent of #:IGNORE, so it matches anything and
    discards it (??? probably an invalid interpretation of the standard)

A & B differ in that A thinks that () is the symbol NIL which is a
constant which cannot be bound, while B thinks that () is an empty
destructuring lambda list which should match another empty lambda list.

So, what is the correct behavior here?

-- 
Sam Steingold (http://www.podval.org/~sds) running w2k
<http://www.camera.org> <http://www.iris.org.il> <http://www.memri.org/>
<http://www.mideasttruth.com/> <http://www.honestreporting.com>
What's the difference between Apathy & Ignorance? -I don't know and don't care!

From: Antonio Menezes Leitao
Subject: Re: empty lists in destructuring
Date: 
Message-ID: <pan.2004.05.23.08.05.20.205148@evaluator.pt>
On Sun, 23 May 2004 03:02:14 -0400, Sam Steingold wrote:

> is it OK for a destructuring lambda list to have NIL elements?
> (i.e., empty subtrees)
> 
> E.g., what should
>       (macrolet ((%m (()) :good)) (%m ()))
> and
>       (macrolet ((%m (()) :good)) (%m 10))
> return?
> 
> A.  NIL cannot be bound so both should signal an error (CLISP)
> 
> B.  () matches (), so the first form returns :GOOD, while 10 does not
>     match (), so the second form signals an error (LWW)
> 
> C.  () is an equivalent of #:IGNORE, so it matches anything and
>     discards it (??? probably an invalid interpretation of the standard)
> 
> A & B differ in that A thinks that () is the symbol NIL which is a
> constant which cannot be bound, while B thinks that () is an empty
> destructuring lambda list which should match another empty lambda list.
> 
> So, what is the correct behavior here?

I'll repeat my argument:

According to the Hyperspec,

  Anywhere in a macro lambda list where a parameter name can appear, and
  where ordinary lambda list syntax (as described in Section 3.4.1
  (Ordinary Lambda Lists)) does not otherwise allow a list, a
  destructuring lambda list can appear in place of the parameter name.
  When this is done, then the argument that would match the parameter is
  treated as a (possibly dotted) list, to be used as an _argument list_
  for satisfying the parameters in the embedded _lambda list_. This is
  known as destructuring.

Obviously, the concepts of _argument list_ and _lambda list_ include the
empty list. (I couldn't find anything that says otherwise).

This means that I can write a macro call containing an empty list "to be
used as an argument list for satisfying the parameters in the embedded
lambda list":

(macro ... () ...)

The macro lambda list must contain an embedded lambda list that matches
the empty list.  The unique solution is:

(defmacro macro (... () ...)
  ...)

Antonio Leitao.
From: Sam Steingold
Subject: Re: empty lists in destructuring
Date: 
Message-ID: <ubrkf12tl.fsf@gnu.org>
> * Antonio Menezes Leitao <··············@rinyhngbe.cg> [2004-05-23 09:05:20 +0100]:
>
> On Sun, 23 May 2004 03:02:14 -0400, Sam Steingold wrote:
>
>> is it OK for a destructuring lambda list to have NIL elements?
>> (i.e., empty subtrees)
>> 
>> E.g., what should
>>       (macrolet ((%m (()) :good)) (%m ()))
>> and
>>       (macrolet ((%m (()) :good)) (%m 10))
>> return?
>> 
>> A.  NIL cannot be bound so both should signal an error (CLISP)
>> 
>> B.  () matches (), so the first form returns :GOOD, while 10 does not
>>     match (), so the second form signals an error (LWW)
>> 
>> C.  () is an equivalent of #:IGNORE, so it matches anything and
>>     discards it (??? probably an invalid interpretation of the standard)
>> 
>> A & B differ in that A thinks that () is the symbol NIL which is a
>> constant which cannot be bound, while B thinks that () is an empty
>> destructuring lambda list which should match another empty lambda list.
>> 
>> So, what is the correct behavior here?
>
> I'll repeat my argument:

So you think B is valid.  Good.
What about A?  Why isn't it valid too?
You see, "empty list" and "symbol NIL" is the exact same object in
Common Lisp, so when you write

> (defmacro macro (... () ...)
>   ...)

it is not clear whether you have an empty argument list (valid) or a
binding for constant symbol NIL (illegal).


-- 
Sam Steingold (http://www.podval.org/~sds) running w2k
<http://www.camera.org> <http://www.iris.org.il> <http://www.memri.org/>
<http://www.mideasttruth.com/> <http://www.honestreporting.com>
WHO ATE MY BREAKFAST PANTS?
From: Thomas F. Burdick
Subject: Re: empty lists in destructuring
Date: 
Message-ID: <xcvzn7yubym.fsf@famine.OCF.Berkeley.EDU>
Sam Steingold <···@gnu.org> writes:

> What about A?  Why isn't it valid too?

Because it raises an error when given a valid argument list.

> You see, "empty list" and "symbol NIL" is the exact same object in
> Common Lisp, so when you write
> 
> > (defmacro macro (... () ...)
> >   ...)
> 
> it is not clear whether you have an empty argument list (valid) or a
> binding for constant symbol NIL (illegal).

An empty argument list is a valid argument list; NIL is not a valid
parameter; argument lists are valid in place of parameters in
destructuring lambda lists.  Since NIL is not a valid parameter, I
don't see how there's any conflict: it can't be a parameter, it must
be an empty argument list!

-- 
           /|_     .-----------------------.                        
         ,'  .\  / | No to Imperialist war |                        
     ,--'    _,'   | Wage class war!       |                        
    /       /      `-----------------------'                        
   (   -.  |                               
   |     ) |                               
  (`-.  '--.)                              
   `. )----'                               
From: Antonio Leitao
Subject: Re: empty lists in destructuring
Date: 
Message-ID: <2318cecf.0405232242.713ac8c5@posting.google.com>
Sam Steingold <···@gnu.org> wrote in message news:<·············@gnu.org>...
> > * Antonio Menezes Leitao <··············@rinyhngbe.cg> [2004-05-23 09:05:20 +0100]:
> >
> > On Sun, 23 May 2004 03:02:14 -0400, Sam Steingold wrote:
> >
> >> is it OK for a destructuring lambda list to have NIL elements?
> >> (i.e., empty subtrees)
> >> 
> >> E.g., what should
> >>       (macrolet ((%m (()) :good)) (%m ()))
> >> and
> >>       (macrolet ((%m (()) :good)) (%m 10))
> >> return?
> >> 
> >> A.  NIL cannot be bound so both should signal an error (CLISP)
> >> 
> >> B.  () matches (), so the first form returns :GOOD, while 10 does not
> >>     match (), so the second form signals an error (LWW)
> >> 
> >> C.  () is an equivalent of #:IGNORE, so it matches anything and
> >>     discards it (??? probably an invalid interpretation of the standard)
> >> 
> >> A & B differ in that A thinks that () is the symbol NIL which is a
> >> constant which cannot be bound, while B thinks that () is an empty
> >> destructuring lambda list which should match another empty lambda list.
> >> 
> >> So, what is the correct behavior here?
> >
> > I'll repeat my argument:
> 
> So you think B is valid.  Good.
> What about A?  Why isn't it valid too?
> You see, "empty list" and "symbol NIL" is the exact same object in
> Common Lisp, so when you write
> 
> > (defmacro macro (... () ...)
> >   ...)
> 
> it is not clear whether you have an empty argument list (valid) or a
> binding for constant symbol NIL (illegal).

I understand your argument and I've stated previously that this looks
like a contradiction in the specification.  This implies that, either
accepting () or rejecting it, your view will be contrary to some part
of the specification.  So, my argument becomes: it is more _useful_ to
accept () than to reject it both because accepting it has no serious
consequences and because rejecting it prevents you from a (I think
legitimate) form of use.

Antonio Leitao
From: Kaz Kylheku
Subject: Re: empty lists in destructuring
Date: 
Message-ID: <cf333042.0405271200.4dc8e3b2@posting.google.com>
Sam Steingold <···@gnu.org> wrote in message news:<·············@gnu.org>...
> > * Antonio Menezes Leitao <··············@rinyhngbe.cg> [2004-05-23 09:05:20 +0100]:
> >
> > On Sun, 23 May 2004 03:02:14 -0400, Sam Steingold wrote:
> >
> >> is it OK for a destructuring lambda list to have NIL elements?
> >> (i.e., empty subtrees)
> >> 
> >> E.g., what should
> >>       (macrolet ((%m (()) :good)) (%m ()))
> >> and
> >>       (macrolet ((%m (()) :good)) (%m 10))
> >> return?
> >> 
> >> A.  NIL cannot be bound so both should signal an error (CLISP)
> >> 
> >> B.  () matches (), so the first form returns :GOOD, while 10 does not
> >>     match (), so the second form signals an error (LWW)
> >> 
> >> C.  () is an equivalent of #:IGNORE, so it matches anything and
> >>     discards it (??? probably an invalid interpretation of the standard)
> >> 
> >> A & B differ in that A thinks that () is the symbol NIL which is a
> >> constant which cannot be bound, while B thinks that () is an empty
> >> destructuring lambda list which should match another empty lambda list.
> >> 
> >> So, what is the correct behavior here?
> >
> > I'll repeat my argument:
> 
> So you think B is valid.  Good.
> What about A?  Why isn't it valid too?
> You see, "empty list" and "symbol NIL" is the exact same object in
> Common Lisp, so when you write
> 
> > (defmacro macro (... () ...)
> >   ...)
> 
> it is not clear whether you have an empty argument list (valid) or a
> binding for constant symbol NIL (illegal).

The only difference between these interpretation is that the first one
allows a destructuring pattern match for NIL and rejects everything
else. Whereas the second interpretation rejects everything.

Does the liberal interpretation carry any risk that programs will be
misinterpreted? That the programmer intended one thing, but the
behavior was otherwise?

The answer is no. Because if the programmer expects NIL to behave as a
constant denoting the empty list or false, and expects a destructuring
pattern match to work, then he expects these results:

  (defmacro my-quote (nil)
    `(quote ,nil))  ;; constant is evaluated here

  (my-quote nil) -> NIL  ;; yep, nil matches nil, call is valid!

And if the programmer is very inexperienced and does not understand
that NIL cannot be used as a variable name, he also expects these same
results:

   (defmacro my-quote (nil)
     `(quote ,nil))  ;; expects variable evaluation here

   (my-quote nil) --> NIL   ;; yep, NIL got bound to the value NIL!

There is no utility in rejecting cases whose expected behavior is the
same regardless of the programmer's misunderstanding of his own code
and the programming language.
From: Pascal Costanza
Subject: Re: empty lists in destructuring
Date: 
Message-ID: <c8r6ju$43s$1@newsreader2.netcologne.de>
Sam Steingold wrote:
> is it OK for a destructuring lambda list to have NIL elements?
> (i.e., empty subtrees)
> 
> E.g., what should
>       (macrolet ((%m (()) :good)) (%m ()))
> and
>       (macrolet ((%m (()) :good)) (%m 10))
> return?
> 
> A.  NIL cannot be bound so both should signal an error (CLISP)
> 
> B.  () matches (), so the first form returns :GOOD, while 10 does not
>     match (), so the second form signals an error (LWW)
> 
> C.  () is an equivalent of #:IGNORE, so it matches anything and
>     discards it (??? probably an invalid interpretation of the standard)
> 
> A & B differ in that A thinks that () is the symbol NIL which is a
> constant which cannot be bound, while B thinks that () is an empty
> destructuring lambda list which should match another empty lambda list.
> 
> So, what is the correct behavior here?

We had a discussion about this issue here recently, and my conclusions 
were that this is not the right question to ask. I think the better 
question is: What do you gain from disallowing NIL in a macro lambda list?

Anyway, the relevant section in the HyperSpec is 3.4.4.1: "Anywhere in a 
macro lambda list where a parameter name can appear, and where ordinary 
lambda list syntax (as described in Section 3.4.1 (Ordinary Lambda 
Lists)) does not otherwise allow a list, a destructuring lambda list can 
appear in place of the parameter name."

The glossary says that a destructuring lambda list is a special kind of 
extended lambda list, which is a special kind of ordinary lambda list, 
which is a special kind of lambda list, which is a special kind of list. 
NIL is a list. q.e.d. ;)

Pascal

-- 
1st European Lisp and Scheme Workshop
June 13 - Oslo, Norway - co-located with ECOOP 2004
http://www.cs.uni-bonn.de/~costanza/lisp-ecoop/