From: Piercarlo Slavazza
Subject: Replacing elements in a list
Date: 
Message-ID: <0gq0u8.ih2.ln@localhost.localdomain>
Hi! I started yesterday programming in lisp and now I've got my first
problem... Suppose that I have a list l1 and a list l2: how can I replace
the nth element in list l1 with list l2? (The resulting list should be
flat) Maybe it should be better modify the structure of l1 than create a
brand new list with the features desired...

Thanks!!! piercarlo

P.S.: I use GCL 2.2.2

From: Rainer Joswig
Subject: Re: Replacing elements in a list
Date: 
Message-ID: <joswig-9B2299.14591904112000@news.is-europe.net>
In article <·············@localhost.localdomain>, "Piercarlo Slavazza" 
<··········@libero.it> wrote:

> Hi! I started yesterday programming in lisp and now I've got my first
> problem... Suppose that I have a list l1 and a list l2: how can I replace
> the nth element in list l1 with list l2? (The resulting list should be
> flat) Maybe it should be better modify the structure of l1 than create a
> brand new list with the features desired...
> 
> Thanks!!! piercarlo
> 
> P.S.: I use GCL 2.2.2

Modify something like this:

(defun splice (l1 l2 n)
  (if (zerop n)
    (nconc l2 l1)
    (progn
      (nconc l2 (nthcdr n l1))
      (setf (nthcdr n l1) l2)
      l1)))

-- 
Rainer Joswig, Hamburg, Germany
Email: ·············@corporate-world.lisp.de
Web: http://corporate-world.lisp.de/
From: Piercarlo Slavazza
Subject: Re: Replacing elements in a list
Date: 
Message-ID: <ug93u8.hn1.ln@localhost.localdomain>
Nell'articolo <····························@news.is-europe.net>, "Rainer
Joswig" <······@corporate-world.lisp.de> ha scritto:

> In article <·············@localhost.localdomain>, "Piercarlo Slavazza" 
> <··········@libero.it> wrote:
> 
>> ...
>> P.S.: I use GCL 2.2.2
> 
> Modify something like this:
> 
> (defun splice (l1 l2 n)
>   (if (zerop n)
>     (nconc l2 l1)
>     (progn
>       (nconc l2 (nthcdr n l1))
>       (setf (nthcdr n l1) l2)
>       l1)))
> 

Well, (nconc l2 l1) should be replaced by (nconc l2 (cdr l1))... Besides
that, please look at this:
>(setf a '(1 2 3))
(1 2 3)

>(setf b '(4 5))
(4 5)

>(splice a b 1)

Error: Cannot expand the SETF form (NTHCDR N L1). Fast links are on: do
(si::use-fast-links nil) for debugging Error signalled by SETF. Broken at
SYSTEM::SETF-HELPER.  Type :H for Help.
>>

This is the main problem I encountered in my trials: I cannot use nthcdr
in a setf....

Anyway... thanks!!! piercarlo
From: Rainer Joswig
Subject: Re: Replacing elements in a list
Date: 
Message-ID: <joswig-B105DA.09245507112000@news.is-europe.net>
In article <·············@localhost.localdomain>, "Piercarlo Slavazza" 
<··········@libero.it> wrote:

> 
> Error: Cannot expand the SETF form (NTHCDR N L1). Fast links are on: do
> (si::use-fast-links nil) for debugging Error signalled by SETF. Broken at
> SYSTEM::SETF-HELPER.  Type :H for Help.
> >>
> 
> This is the main problem I encountered in my trials: I cannot use nthcdr
> in a setf....

Use something like this:

(defun set-nthcdr (n list item)
  (let ((cell (nthcdr (1- n) list)))
    (if cell
      (setf (cdr cell) item)))
  list)

(defsetf nthcdr set-nthcdr)

-- 
Rainer Joswig, Hamburg, Germany
Email: ·············@corporate-world.lisp.de
Web: http://corporate-world.lisp.de/
From: Kent M Pitman
Subject: Re: Replacing elements in a list
Date: 
Message-ID: <sfwu29kccvy.fsf@world.std.com>
Rainer Joswig <······@corporate-world.lisp.de> writes:

> In article <·············@localhost.localdomain>, "Piercarlo Slavazza" 
> <··········@libero.it> wrote:
> 
> > Error: Cannot expand the SETF form (NTHCDR N L1). Fast links are on: do
> > (si::use-fast-links nil) for debugging Error signalled by SETF. Broken at
> > SYSTEM::SETF-HELPER.  Type :H for Help.
> > >>
> > 
> > This is the main problem I encountered in my trials: I cannot use nthcdr
> > in a setf....
> 
> Use something like this:
> 
> (defun set-nthcdr (n list item)
>   (let ((cell (nthcdr (1- n) list)))
>     (if cell
>       (setf (cdr cell) item)))
>   list)
> 
> (defsetf nthcdr set-nthcdr)

Except, of course, that you as a programmer aren't allowed to setf
NTHCDR because the spec prohibits this.  (CLHS 11.1.2.1.2 item 13)

I don't see a restriction against an implementation offering this
(CLHS 11.1.2.1.1) but I'm not sure why.  
Underlying issue PACKAGE-CLUTTER:REDUCE specifically enumerates
setf methods as one of the things implementations must not do, so 
either I made an editorial error here (pity) or else there's a 
later issue that superseded this one that I didn't xref when I made 
the change (a sort of editorial error in itself).  
In any case, I think personally it's "poor form" (if not "nonconforming")
for an implementation to provide unwanted setfs.

I'd just use the function call above, not the SETF, or I'd shadow NTHCDR
and make a new NTHCDR of my own that could be SETFable without trampling
on the system symbol.  

One reason for not trying to defsetf nthcdr is that the system might 
signal an error.  A second reason, though, is that other packages share
that same symbol and might do the same thing--if you have that right,
so do they.  If you trust everyone else in the world to (a) be as good
a programmer as you and (b) come up with the identical error handling
such that your program doesn't mind using their version of this function
sight unseen if the load-order of the system is bad, then I guess this
second concern is a nonconcern.  But maybe they'll write:

 (DEFUN SET-NTHCDR (N LIST ITEM) ;bad guys program in uppercase, right?
   (LET ((CELL (NTHCDR (1- N) LIST)))
     (UNLESS CELL (ERROR "SETF NTHCDR of ~D - List too short: ~S" n list))
     (SETF (CDR CELL) ITEM))
   ITEM) ;return the "place value", not the whole list

- - -

Personally, by the way, I don't know that I feel very good about
NTH or ELT having a SETF because it makes it so easy for people to
write code with bad algorithmic performance; a simple loop down n
elements having O(n^2) performance if you use SETF of NTH or ELT.
And the problem with SETF of NTHCDR is similar, performancewise,
making it--like APPEND--not the way to go in most cases.
From: Rainer Joswig
Subject: Re: Replacing elements in a list
Date: 
Message-ID: <joswig-4E2C47.11293107112000@news.is-europe.net>
In article <···············@world.std.com>, Kent M Pitman 
<······@world.std.com> wrote:

> > (defsetf nthcdr set-nthcdr)
> 
> Except, of course, that you as a programmer aren't allowed to setf
> NTHCDR because the spec prohibits this.  (CLHS 11.1.2.1.2 item 13)

Seems like I'm walking over a mine field... ;-)

> I don't see a restriction against an implementation offering this
> (CLHS 11.1.2.1.1) but I'm not sure why.  

MCL does offer it.

> In any case, I think personally it's "poor form" (if not "nonconforming")
> for an implementation to provide unwanted setfs.

Hmm...

> I'd just use the function call above, not the SETF, or I'd shadow NTHCDR
> and make a new NTHCDR of my own that could be SETFable without trampling
> on the system symbol.  

I agree.


> Personally, by the way, I don't know that I feel very good about
> NTH or ELT having a SETF because it makes it so easy for people to
> write code with bad algorithmic performance; a simple loop down n
> elements having O(n^2) performance if you use SETF of NTH or ELT.
> And the problem with SETF of NTHCDR is similar, performancewise,
> making it--like APPEND--not the way to go in most cases.

I was really expecting it to be part of CL. Well...

-- 
Rainer Joswig, Hamburg, Germany
Email: ·············@corporate-world.lisp.de
Web: http://corporate-world.lisp.de/
From: Kent M Pitman
Subject: Re: Replacing elements in a list
Date: 
Message-ID: <sfwofzs6k14.fsf@world.std.com>
Rainer Joswig <······@corporate-world.lisp.de> writes:

> > Personally, by the way, I don't know that I feel very good about
> > NTH or ELT having a SETF because it makes it so easy for people to
> > write code with bad algorithmic performance; a simple loop down n
> > elements having O(n^2) performance if you use SETF of NTH or ELT.
> > And the problem with SETF of NTHCDR is similar, performancewise,
> > making it--like APPEND--not the way to go in most cases.
> 
> I was really expecting it to be part of CL. Well...

Given that NTH and ELT are there, the algorithmic arguments are out the
window.  I was thinking it was the error handling that was the problem.
But now that I think harder, it might be the zero case.  I don't think
your SETF correctly handles 
 (setf (nthcdr 0 x) foo)
which some contend should do 
 (setq x foo)
I think others thought this was overkill or confusing or something.
I'm not sure why.  Doesn't setf of getf do a similar thing?
Anyway, whether it was this or the error handling, it was some fringe
issue that was the reason NTHCDR was left out.  It wasn't an accident.
It was the result of some dispute.  Maybe Barmar or Haflich or someone
remembers better..
From: Rainer Joswig
Subject: Re: Replacing elements in a list
Date: 
Message-ID: <joswig-736081.02293408112000@news.is-europe.net>
In article <···············@world.std.com>, Kent M Pitman 
<······@world.std.com> wrote:

> Rainer Joswig <······@corporate-world.lisp.de> writes:
> 
> > > Personally, by the way, I don't know that I feel very good about
> > > NTH or ELT having a SETF because it makes it so easy for people to
> > > write code with bad algorithmic performance; a simple loop down n
> > > elements having O(n^2) performance if you use SETF of NTH or ELT.
> > > And the problem with SETF of NTHCDR is similar, performancewise,
> > > making it--like APPEND--not the way to go in most cases.
> > 
> > I was really expecting it to be part of CL. Well...
> 
> Given that NTH and ELT are there, the algorithmic arguments are out the
> window.  I was thinking it was the error handling that was the problem.
> But now that I think harder, it might be the zero case.  I don't think
> your SETF correctly handles 
>  (setf (nthcdr 0 x) foo)
> which some contend should do 
>  (setq x foo)
> I think others thought this was overkill or confusing or something.
> I'm not sure why.  Doesn't setf of getf do a similar thing?

The MCL implementation does not support (setf (nthcdr 0 x) foo) .

> Anyway, whether it was this or the error handling, it was some fringe
> issue that was the reason NTHCDR was left out.  It wasn't an accident.
> It was the result of some dispute.  Maybe Barmar or Haflich or someone
> remembers better..

Thanks for pointing this out. I'll send an email to Digitool.

-- 
Rainer Joswig, Hamburg, Germany
Email: ·············@corporate-world.lisp.de
Web: http://corporate-world.lisp.de/
From: Pekka P. Pirinen
Subject: Re: Replacing elements in a list
Date: 
Message-ID: <ixitpxge3o.fsf@harlequin.co.uk>
Kent M Pitman <······@world.std.com> writes:
> But now that I think harder, it might be the zero case.  I don't think
> your SETF correctly handles 
>  (setf (nthcdr 0 x) foo)
> which some contend should do 
>  (setq x foo)

That's what I thought when I wrote it for LWW.  For some reason, it's
never been ported to the Unix Lisps.  If you want to, you can (except
that it's non-standard, as Kent pointed out):

(define-setf-method nthcdr (n list &environment env)
  (multiple-value-bind (temps vals stores store-form access-form)
      (get-setf-method list env)
    (with-unique-names (ntemp store)
      (let ((stemp (first stores)))
        (values (cons ntemp temps)
	        (cons n vals)
	        (list store)
	        `(let ((,stemp (set-nthcdr ,ntemp ,access-form ,store)))
		   ,store-form
		   ,store)
	        `(nthcdr ,ntemp ,access-form))))))

where SET-NTHCDR is as Rainer wrote, and WITH-UNIQUE-NAMES is left as
an exercise for those not using a Xanalys Lisp.
-- 
Pekka P. Pirinen, Adaptive Memory Management Group, Harlequin Limited
A feature is a bug with seniority.  - David Aldred <david_aldred.demon.co.uk>
From: Kent M Pitman
Subject: Re: Replacing elements in a list
Date: 
Message-ID: <sfwem0ry95c.fsf@world.std.com>
"Piercarlo Slavazza" <··········@libero.it> writes:

> Hi! I started yesterday programming in lisp and now I've got my first
> problem... Suppose that I have a list l1 and a list l2: how can I replace
> the nth element in list l1 with list l2? (The resulting list should be
> flat) Maybe it should be better modify the structure of l1 than create a
> brand new list with the features desired...

You should state clearly whether you are quoting the actual problem text
that you were assigned to do, or whether you are telling us a small subproblem
of a larger assignment.  No one here wants to think they're doing another's
homework for them.

As an aside, if the resulting list is to be flat, the terminology you have
used is non-standard for describing your result.  An "element" means the
thing at a given position in a list, regardless of whether it is a list or not.
Replace means to remove an "element" and replace it with a replacement
"element".  The length of a list, for example, never changes when an element
is replaced.  If l2 is a list, and the resulting list after replacing an
element of l1 contains no lists, then what you did is not called element
replacement.

The process of adding a list to the end of another list, such that the result
is the concatenation of the two lists is called appending.  If done 
destructively (changing the backbone structure of the first list rather than
copying the backbone structure of the first list in the process), we use
a function called NCONC (pronounced EN-conk).  When the same operation is
done such that the elements of the list are inserted into the middle of a list,
destructively, we say we want to "splice one list into another", but there is
no operation for doing that.  It may be this that you mean to be doing.

The choice of whether to be destructive or not has to do with several factors,
but none of them (at least for now, for you) should be "whether it produces
garbage".  Lisp has a garbage collector that will clean up lost pointers.
If other structures have pointers to the list into which you will splice, you
must determine whether those other structures want to see the update you're
making.  If so, then you must splice destructively.  If those other structures
definitely do not, then you must do it non-destructively.  If those other
structures either do not care or if there are no such other structures, then
you are free to do what feels either fastest to execute or simplest to debug
or to optimize some other quality that matters to you personally.

Mostly I would expect that an instructor would have told you some or 
all of this before assigning it to you as a problem, so it might be good to
review your notes or the book you're working from to make sure you're not
missing something.  Instructors usually do not assign problems where they 
leave it open to a person to decide between destructive/non-destructive
without having already taught both and wanting you to learn on your 
own when to use one or the other.  And usually if they haven't taught both
they want you to do it a specific way, since the skill of programming a 
non-destructive version is very different than the skill of programming a
destructive one, and they usually want to keep track of what skills they
have taught you.

Anyway, I hope some of the above helps.  Sorry there's no code to go with it.
I hate accidentally doing someone's homework and never volunteer more help
until the assigned problem has been stated clearly enough that I'm sure
I'm not treading on what the instructor means you, the student, to do.
Homework assignments are learning exercises and they do little good if we end
up doing them instead of you...
From: Piercarlo Slavazza
Subject: Re: Replacing elements in a list
Date: 
Message-ID: <hla3u8.3s1.ln@localhost.localdomain>
Nell'articolo <···············@world.std.com>, "Kent M Pitman"
<······@world.std.com> ha scritto:

> "Piercarlo Slavazza" <··········@libero.it> writes:
> 
>> ...
> 
> You should state clearly whether you are quoting the actual problem text
> that you were assigned to do, or whether you are telling us a small
> subproblem of a larger assignment.  No one here wants to think they're
> doing another's homework for them.
Don't worry!!!! I'm telling you "a small subproblem of a (very) larger
assignment", which is my degree thesis :) !!!! To be more precise, it is
on combined word problems...

> As an aside, if the resulting list is to be flat, the terminology you
> ...
> It may be this that you mean to be doing.
Yeah, it is! As an aside, I appreciate your remarks on terminology,
because I'm not familiar with this...

> The choice of whether to be destructive or not has to do with several
> ...
> some other quality that matters to you personally.
I think that in my task is useful to be destructive; anyway, for now, I
found a non-destructive solution, but I'm looking for a destructive one.
 
> Mostly I would expect that an instructor would have told you some or 
I'm learning Lisp by myself... :(( so, any advice is very helpful!!!!

Thanks!!
piercarlo
From: Tim Bradshaw
Subject: Re: Replacing elements in a list
Date: 
Message-ID: <ey34s1nb7xh.fsf@cley.com>
* Piercarlo Slavazza wrote:
> Hi! I started yesterday programming in lisp and now I've got my
> first problem... Suppose that I have a list l1 and a list l2: how
> can I replace the nth element in list l1 with list l2? (The
> resulting list should be flat) Maybe it should be better modify the
> structure of l1 than create a brand new list with the features
> desired...

Here is one way.

(defun splice-nth (l1 n l2)
  ;; splice (non-destructively) l2 into l1 at n
  ((lambda (c)
     (funcall c c l1 n))
   (lambda (c l1 n)
     (if (zerop n)
      ((lambda (c)
	 (funcall c c l2 (cdr l1)))
       (lambda (c l1 l2)
	 (if (null l1)
	     l2
	     (cons (car l1)
		   (funcall c c (cdr l1) l2)))))
	 (cons (car l1) 
	       (funcall c c (cdr l1) (1- n)))))))


      
     
From: Kenny Tilton
Subject: Re: Replacing elements in a list
Date: 
Message-ID: <3A071D37.401B1465@nyc.rr.com>
Piercarlo Slavazza wrote:

> Hi! I started yesterday programming in lisp and now I've got my first
> problem... Suppose that I have a list l1 and a list l2: how can I replace
> the nth element in list l1 with list l2? (The resulting list should be
> flat) Maybe it should be better modify the structure of l1 than create a
> brand new list with the features desired...
>
> Thanks!!! piercarlo
>
> P.S.: I use GCL 2.2.2

Two answers:

(a) (defun nsplice (l1 n l2) ;; this is destructive version
        (when (< -1 n (length l1))
            (let* ((prior (when (plusp n)
                     (nthcdr (1- n) l1)))
                     (target (or (cdr prior)
                                     (nthcdr n l1)))
                     (remainder (cdr target)))

             (when prior
                  (rplacd prior l2))

             (rplacd (last l2) remainder)

             (if prior l1 l2))))

(b)  That's a pretty wild requirement to have after one day...what's the big
picture? What are you trying to do?

kenny