hey,
I'm trying to figure out why ACL doesn't define a SETF method for
NTHCDR. I tried doing:
(setf (nthcdr 5 my-list) blah)
and it failed. The people at franz told me to do, instead:
(setf (cdr (nthcdr 4 my-list) blah))
and said that this was more portable CL. I don't understand why
(setf nthcdr) is not portable. Is it the case that the CL spec
specifies what SETF methods must exist?
thanks,
dave
In article <···············@engc.bu.edu>, David Bakhash <·····@bu.edu> wrote:
> hey,
>
> I'm trying to figure out why ACL doesn't define a SETF method for
> NTHCDR. I tried doing:
>
> (setf (nthcdr 5 my-list) blah)
>
> and it failed. The people at franz told me to do, instead:
>
> (setf (cdr (nthcdr 4 my-list) blah))
>
> and said that this was more portable CL. I don't understand why
>
> (setf nthcdr) is not portable. Is it the case that the CL spec
> specifies what SETF methods must exist?
See: ANSI CL HyperSpec: 5.1.2.2 Function Call Forms as Places
--
http://www.lavielle.com/~joswig
In article <···············@engc.bu.edu>, David Bakhash <·····@bu.edu> wrote:
>and said that this was more portable CL. I don't understand why
>(setf nthcdr) is not portable. Is it the case that the CL spec
>specifies what SETF methods must exist?
I can't for the life of me remember why we didn't make this a standard
SETFable place. Maybe Kent does. It could be we simply didn't think of
it, but I vaguely remember it coming up.
--
Barry Margolin, ······@bbnplanet.com
GTE Internetworking, Powered by BBN, Burlington, MA
*** DON'T SEND TECHNICAL QUESTIONS DIRECTLY TO ME, post them to newsgroups.
Barry Margolin <······@bbnplanet.com> writes:
> In article <···············@engc.bu.edu>, David Bakhash <·····@bu.edu> wrote:
> >and said that this was more portable CL. I don't understand why
> >(setf nthcdr) is not portable. Is it the case that the CL spec
> >specifies what SETF methods must exist?
>
> I can't for the life of me remember why we didn't make this a standard
> SETFable place. Maybe Kent does. It could be we simply didn't think of
> it, but I vaguely remember it coming up.
someone at Franz said it's because of the non-sensical issue of
(nthcar 0 lst)
which (as we know) returns the list. Here's part of our email
conversation...
From: David Bakhash <·····@bu.edu>
> (defun nbutlastx (list &optional (n 1))
> (setf (nthcdr (max 0 (- (length list) n)) list) nil)
> list)
>
> Clearly this fails if n equals the length of the list.
all these examples are wrong in that they assume that (setf nthcdr)
doesn't check for the first arg to nthcdr being 0. now, *THAT* would
be nonsensical. Here's what I mean:
(defun set-nthcdr-internal (n list x)
(if (<= n 0) x (setf (cdr (nthcdr (1- n) list) x)) list))
and then work this in with defsetf for NTHCDR
If you mean that you might specify this as the update-fn in the simple
form of defsetf, clearly that won't work and cannot work for the 0
case:
<8> (compile
(defun set-nthcdr-internal (n list x)
(if (<= n 0)
x
(setf (cdr (nthcdr (1- n) list)) x))
list))
set-nthcdr-internal
nil
nil
<9> (defsetf nthcdr set-nthcdr-internal)
Error: Attempt to make a defsetf definition for the name nthcdr. This name ...
[1c] <10> :cont
nthcdr
<11> (setf (nthcdr 2 (setq l (list 1 2 3 4 5))) 'z)
(1 2 . z)
<12> (setf (nthcdr 0 (setq l (list 1 2 3 4 5))) 'z)
(1 2 3 4 5)
<13> l
(1 2 3 4 5)
The difficulty is that in the 0 case setf the list argument subform to
nthcdr _must_ be a "place acceptable to setf" and that place subform
must be accessible to the setf expander if setf is to be able to
modify it.
I think something like this implements a setfable alternative to
nthcdr, but I'd want to think a lot more about the semantic
constraints on the setf expansion before I would publish such a think
-- especially regarding the consistent treatment and ordered execution
of the argument subforms such as in this nonsense form
(setf (nthcdr1 (random (incf foo))
(cadr (aref my-list-repository
(if (>= (incf hour) 24)
(setf hour 0)
hour))))
(make-list foo))
I've checked the full macroexpansion and it seems to be correct, but
you see how subtle and counterintuitive these things can be.
==================== nthcdr1.cl
(in-package :user)
(defun nthcdr1 (n list) (nthcdr n list))
(define-compiler-macro nthcdr1 (n list) `(nthcdr ,n ,list))
(define-setf-expander nthcdr1 (n list)
(multiple-value-bind (vars vals stores writer reader)
(get-setf-expansion list)
(let ((nn (gensym)))
(values (list* nn vars)
(list* n vals)
stores
`(if (eql ,nn 0)
,writer
(setf (cdr (nthcdr (1- ,nn) ,reader)) ,(car stores)))
`(nthcdr ,nn ,reader)))))
==================== END
It's also worth considering what happens if the list subform is a
place that hacks multiple values. The expansion might cause unused
variable warnings, etc. etc. It's a lot to think about....
In article <····················@burlma1-snr1.gtei.net>,
Barry Margolin <······@bbnplanet.com> wrote:
>
> I can't for the life of me remember why we didn't make this a standard
> SETFable place. Maybe Kent does. It could be we simply didn't think of
> it, but I vaguely remember it coming up.
>
I think that the issue was in handling what to do when the index is
greater than the length of the source list:
(setq x '(a b c))
(setf (nthcdr 5 x) '(x y z))
Too bad it wasn't decided to be an error...
-- Dan Corkill
-----== Posted via Deja News, The Leader in Internet Discussion ==-----
http://www.dejanews.com/rg_mkgrp.xp Create Your Own Free Member Forum