From: Eliot Handelman
Subject: SETF LAST
Date: 
Message-ID: <3688@phoenix.Princeton.EDU>
More people than anticipated responded to my setf query the other night.
I think I've resolved the issue, here's the summary:

Sometimes it's the case that (eq (last x) x) => T, namely when
x is nil, or consists of a single cons: (y) or (y . z). It's
easy to handle the case where (eq (last x) x) => NIL, as I discovered
shortly after my 3rd posting yesterday, (and which somebody pointed out
shortly after that), as follows:

(defun set-last (list val)
  (rplacd (last (nbutlast list)) val))

(defsetf last set-last)

This works for lists not eq to (last list).  The trouble is that when
eq => T this method generates errors (because it tries to rplacd NIL).
That seems to me inconsistent with the behaviour of last. If I can take
last then I should be able to set it, ie:

(setq x '(a))
(last x) => (a)
(setf (last x) '(b)) should give x => (b)

and

(setq x nil)
(last x) => NIL
(setf (last x) '(a)) should give x => (a).

So the best general method would be this:

(defmacro setlast (list val)
  `(progn 
    (if (eq (last ,list) ,list)
	(setf ,list ,val)
	(rplacd (last (nbutlast ,list)) ,val))
    ,val))

(defsetf last setlast)

It's not nice, because of the IF, but it does the job. Comments?

 -Eliot
-- 
This message will cost the net hundreds if not thousands and perhaps millions
billions trillions maybe even zillions of dollars to send everywhere.