From: Wouter Lievens
Subject: "bug" in NBUTLAST
Date: 
Message-ID: <3dfd9bfb$0$74336$ba620e4c@news.skynet.be>
Look at the last two output lines. I don't get it!! NBUTLAST removes the
last element of a list EXCEPT when the list contains when item. It will
return NIL, but not set the list to NIL. Any explenation?



CG-USER(48): (setf a '(1 2 3))
(1 2 3)
CG-USER(49): a
(1 2 3)
CG-USER(50): (nbutlast a)
(1 2)
CG-USER(51): a
(1 2)
CG-USER(52): (nbutlast a)
(1)
CG-USER(53): a
(1)
CG-USER(54): (nbutlast a)
NIL
CG-USER(55): a
(1)
CG-USER(56):

From: Frode Vatvedt Fjeld
Subject: Re: "bug" in NBUTLAST
Date: 
Message-ID: <2hr8ciuw41.fsf@vserver.cs.uit.no>
"Wouter Lievens" <·········@telefragged.com> writes:

> Look at the last two output lines. I don't get it!! NBUTLAST removes
> the last element of a list EXCEPT when the list contains when
> item. It will return NIL, but not set the list to NIL. Any
> explenation?

You simply haven't yet understood the basic rules of evaluation in
lisp. That's where you should start to look if you want to understand
what's going on. For example, try to write a function that does what
you expected nbutlast to do when given a list of length one. You'll
find that it is impossible, and that should tell you
something. Meanwhile, just remember that you should always do

  (setf <var> (nbutlast <var>))

rather than just (nbutlast <var>). For all the n<foo> functions (and
all other functions too) it is the return value that is the result of
that function, it's not their side-effect. Side-effects should not be
expected or required, they should be _tolerated_ (or banned, by using
a non-destructive function).

-- 
Frode Vatvedt Fjeld
From: Wouter Lievens
Subject: Re: "bug" in NBUTLAST
Date: 
Message-ID: <3dfdac91$0$74337$ba620e4c@news.skynet.be>
"Frode Vatvedt Fjeld" <······@cs.uit.no> schreef in bericht
···················@vserver.cs.uit.no...
> "Wouter Lievens" <·········@telefragged.com> writes:
>
> > Look at the last two output lines. I don't get it!! NBUTLAST removes
> > the last element of a list EXCEPT when the list contains when
> > item. It will return NIL, but not set the list to NIL. Any
> > explenation?
>
> You simply haven't yet understood the basic rules of evaluation in
> lisp. That's where you should start to look if you want to understand
> what's going on. For example, try to write a function that does what
> you expected nbutlast to do when given a list of length one. You'll
> find that it is impossible, and that should tell you
> something. Meanwhile, just remember that you should always do
>
>   (setf <var> (nbutlast <var>))
>
> rather than just (nbutlast <var>). For all the n<foo> functions (and
> all other functions too) it is the return value that is the result of
> that function, it's not their side-effect. Side-effects should not be
> expected or required, they should be _tolerated_ (or banned, by using
> a non-destructive function).
>
> --
> Frode Vatvedt Fjeld


I was, in fact, looking for the side effects. I just wanted a destructive
operation, like the standard POP and PUSH for lists.
I used a macro to do what I wanted. I just figured that it was silly writing
setf various times for exactly the same code...
From: Frode Vatvedt Fjeld
Subject: Re: "bug" in NBUTLAST
Date: 
Message-ID: <2hn0n6urzv.fsf@vserver.cs.uit.no>
"Wouter Lievens" <·········@telefragged.com> writes:

> I was, in fact, looking for the side effects. I just wanted a
> destructive operation, like the standard POP and PUSH for lists.

If this wasn't clear from what I wrote before: You don't understand
what "destructive" means in lingua lisp. Neither push nor pop are
destructive. Since you don't understand "destructive", you are really
not in a position to determine whether you can use nbutlast instead of
butlast.

> I used a macro to do what I wanted. I just figured that it was silly
> writing setf various times for exactly the same code...

This is almost certainly a bad idea. You'd have to have the same form
repeated very many times in order to justify a macro just to save
typing "setf". And if that is the case, you're probably doing
something else wrong.

Push and pop are, together with setf, some of the very few operators
in lisp that modify variables (actually, "places"). In the interest of
code readability I think it is quite important that place-modifying
operations are easily recognizable. That's where much of the beauty of
having an extendable operator like setf lies: You can immediately tell
that a form like

  (setf x (my-peculiar-operator x y z))

is going to modify the variable x, no more and no less. And, equally
important, you can be reasonably confident that

  (my-peculiar-operator x y z)

is _not_ going to modify x, y, or z, and certainly not any other local
variable of yours. You don't want to break that confidence, unless you
have very good reasons for doing so, and then you should pick operator
names that make it clear that it's a modifying operator (e.g. by
including "set", "push", or "pop").

-- 
Frode Vatvedt Fjeld
From: Coby Beck
Subject: Re: "bug" in NBUTLAST
Date: 
Message-ID: <atkee7$1qod$1@otis.netspace.net.au>
"Wouter Lievens" <·········@telefragged.com> wrote in message
······························@news.skynet.be...
>
> I was, in fact, looking for the side effects. I just wanted a destructive
> operation, like the standard POP and PUSH for lists.
> I used a macro to do what I wanted. I just figured that it was silly
writing
> setf various times for exactly the same code...

You may save a few keystrokes, but you lose in ease of understanding your
code.  Even code you wrote yourself is in danger of being impenetrable after
a few weeks of other things.  Frode is giving you very good advice and
infomation BTW...

--
Coby Beck
(remove #\Space "coby 101 @ bigpond . com")
From: Roger Corman
Subject: Re: "bug" in NBUTLAST
Date: 
Message-ID: <3e003e1b.257935591@news.sf.sbcglobal.net>
On Mon, 16 Dec 2002 11:36:05 +0100, "Wouter Lievens" <·········@telefragged.com>
wrote:

>> > Look at the last two output lines. I don't get it!! NBUTLAST removes
>> > the last element of a list EXCEPT when the list contains when
>> > item. It will return NIL, but not set the list to NIL. Any
>> > explenation?
>>
>I was, in fact, looking for the side effects. I just wanted a destructive
>operation, like the standard POP and PUSH for lists.
>I used a macro to do what I wanted. I just figured that it was silly writing
>setf various times for exactly the same code...
>

Wouter,

Frode and others have all given you good advice.
However, what you are looking for, a destructive macro that works on places
(like PUSH and POP) is very easy to write. This is a good time for you to start
learning about them.

(define-modify-macro pop-last () nbutlast)

(setf a (list 10 20 30 40))
(pop-last a)  -> (10 20 30)
(pop-last a) -> (10 20)
(pop-last a) -> (10)
(pop-last a) -> NIL

Just like POP, only it works off the end.

As an exercise do
 (pprint (macroexpand '(remove-last a)))
and figure out how it works. 

Then try writing PUSH-LAST, which pushes on the end of a list.

Roger
From: Kent M Pitman
Subject: Re: "bug" in NBUTLAST
Date: 
Message-ID: <sfwel8fz5ri.fsf@shell01.TheWorld.com>
·····@corman.net (Roger Corman) writes:

> (define-modify-macro pop-last () nbutlast)
> 
> (setf a (list 10 20 30 40))
> (pop-last a)  -> (10 20 30)
> (pop-last a) -> (10 20)
> (pop-last a) -> (10)
> (pop-last a) -> NIL
> 
> Just like POP, only it works off the end.
> 
> As an exercise do
>  (pprint (macroexpand '(remove-last a)))
> and figure out how it works. 

Probably it will help to use '(pop-last a), not '(remove-last a).

By the way, I generally recommend using MACROEXPAND-1 rather than
MACROEXPAND, since often MACROEXPAND will do multiple steps of expansion
at once and obscure some helpful detail.  One can always do:
 (pprint (macroexpand-1 (macroexpand-1 '(pop-last a))))
and contrast it with
 (pprint (macroexpand-1 '(pop-last a)))
if one wants to see what additional expansion is going on during some
second step...

> Then try writing PUSH-LAST, which pushes on the end of a list.

Keep in mind as one does this, though, that while PUSH/POP are O(1)
speed, PUSH-LAST and POP-LAST will be O(n) speed.  This is probably 
a fine example for learning, but it's not something to do in 
production code in most cases.
From: Roger Corman
Subject: Re: "bug" in NBUTLAST
Date: 
Message-ID: <3e00d47e.1025075740@nntp.sonic.net>
On Wed, 18 Dec 2002 15:49:37 GMT, Kent M Pitman <······@world.std.com>
wrote:

>> 
>> As an exercise do
>>  (pprint (macroexpand '(remove-last a)))
>> and figure out how it works. 
>
>Probably it will help to use '(pop-last a), not '(remove-last a).

Yes, I changed the name while editing the post and forgot to change
that. Thanks.

Good comments, Kent.
From: Kaz Kylheku
Subject: Re: "bug" in NBUTLAST
Date: 
Message-ID: <cf333042.0212171005.62b2686d@posting.google.com>
"Wouter Lievens" <·········@telefragged.com> wrote in message news:<·························@news.skynet.be>...
> Look at the last two output lines. I don't get it!! NBUTLAST removes the
> last element of a list EXCEPT when the list contains when item. It will
> return NIL, but not set the list to NIL. Any explenation?
> 
> 
> 
> CG-USER(48): (setf a '(1 2 3))
> (1 2 3)

You shouldn't SETF a variable unless it has been previously defined
using DEFPARAMETER or DEFVAR. This is not defined behavior.

Note that '(1 2 3) is a list constant; it's undefined to try to
destructively manipulate it.

> CG-USER(49): a
> (1 2 3)
> CG-USER(50): (nbutlast a)
> (1 2)

The behavior is now undefined; demons can fly out of your nose.


> CG-USER(54): (nbutlast a)
> NIL
> CG-USER(55): a
> (1)

Note that NBUTLAST has no effect on the value of A. It returns a list
with the last element lopped of, possibly destroying the original
list. If the original list has only one element in it, there *is no
way* to destroy it to produce an empty list. A list consisting of two
cons cells can be destroyed to produce a list consisting of one cons
cell. But one cons cell cannot be destroyed to produce the value NIL!

If you want the behavior to be as if the object named A was being
operated upon, you must ensure that the return value of NBUTLAST is
assigned to the variable A:

   (setf a (nbutlast a))