From: George Sakkis
Subject: nconc and function parameters [newbie]
Date: 
Message-ID: <f20edcb6-8330-4d48-b5a6-64b205c78ead@v4g2000hsf.googlegroups.com>
Hi everyone,

I've been toying with CL for the last few days after a decade or so I
took a class on it and hated it, but perhaps I can appreciate it more
this time around. So I'm playing with destructive list operations and
I stumbled on the following:

CL-USER> (defparameter x '("dummy"))
(nconc x '(1 2 3))
(nconc x '(1 2 3))
(nconc x '(1 2 3))
x

("dummy" 1 2 3 1 2 3 1 2 3)
CL-USER>

So far so good. Now I'm trying to do the same but from within a
function:

CL-USER> (defun foo (x) (nconc x '(1 2 3)))
(defparameter x '("dummy"))
(foo x)
x

("dummy" 1 2 3)
CL-USER>

Again, nothing unexpected. But then if I try to call (foo x) a second
time, it seems it goes into an infinite loop allocating more and more
memory until I kill it. What's happening ?

Thanks,
George

From: Alessio
Subject: Re: nconc and function parameters [newbie]
Date: 
Message-ID: <e805b9b0-c785-4451-ad17-c6e12b88e8de@c23g2000hsa.googlegroups.com>
On 21 Gen, 19:54, George Sakkis <·············@gmail.com> wrote:
> Hi everyone,
>
> I've been toying with CL for the last few days after a decade or so I
> took a class on it and hated it, but perhaps I can appreciate it more
> this time around.

Hello, that's good! Welcome to the group. Concerning your questions:

1. usually the Common Lisp standard does not specify if and how
destructive operations actually modify their arguments. You should
take the "destructive" information as a warning that, for the sake of
efficiency, your Lisp implementation *might* modify the argument(s).
So in general you should use the return value of such functions
instead of their side-effects, as in

(setf var (destructive-operation-on var))

2. moreover, in the code below, you are actually modifying "constant"
data (that is, the value '("dummy") - it's not a freshly consed list,
but a list embedded in program code!). The consequences of doing that
are unspecified, so in general, when you plan to modify a data
structure, you should always ensure that it's freshly created. E.g.
for lists, use the list function:

(defparameter x (list "dummy"))

I hope that solves your problem! Happy Lisping,
Alessio Stalla

> So I'm playing with destructive list operations and
> I stumbled on the following:
>
> CL-USER> (defparameter x '("dummy"))
> (nconc x '(1 2 3))
> (nconc x '(1 2 3))
> (nconc x '(1 2 3))
> x
>
> ("dummy" 1 2 3 1 2 3 1 2 3)
> CL-USER>
>
> So far so good. Now I'm trying to do the same but from within a
> function:
>
> CL-USER> (defun foo (x) (nconc x '(1 2 3)))
> (defparameter x '("dummy"))
> (foo x)
> x
>
> ("dummy" 1 2 3)
> CL-USER>
>
> Again, nothing unexpected. But then if I try to call (foo x) a second
> time, it seems it goes into an infinite loop allocating more and more
> memory until I kill it. What's happening ?
>
> Thanks,
> George
From: George Sakkis
Subject: Re: nconc and function parameters [newbie]
Date: 
Message-ID: <7d697323-a86c-4c17-bd01-62de995bcf08@v17g2000hsa.googlegroups.com>
On Jan 21, 2:23 pm, Alessio <·············@gmail.com> wrote:

> On 21 Gen, 19:54, George Sakkis <·············@gmail.com> wrote:
>
> > Hi everyone,
>
> > I've been toying with CL for the last few days after a decade or so I
> > took a class on it and hated it, but perhaps I can appreciate it more
> > this time around.
>
> 2. moreover, in the code below, you are actually modifying "constant"
> data (that is, the value '("dummy") - it's not a freshly consed list,
> but a list embedded in program code!). The consequences of doing that
> are unspecified, so in general, when you plan to modify a data
> structure, you should always ensure that it's freshly created. E.g.
> for lists, use the list function:
>
> (defparameter x (list "dummy"))
>
> I hope that solves your problem! Happy Lisping,
> Alessio Stalla


Great, thanks! I thought (list some items) was equivalent to '(some
items); now it makes sense.

On to the second pitfall, I was surprised to find out that the empty
list is a singleton; one can't generate a fresh empty list!

CL-USER> (eq (list) ())
T

Regardless of whether this is a conscious decision or a historic
accident, how can one implement the accumulator idiom, i.e. setting up
an empty list and appending to it ? For instance I tried to translate
from Python the following trivial snippet:

def accum(x, memo=[]):
  memo.append(x)
  return memo

>>> accum(1)
[1]
>>> accum(2)
[1, 2]

I came up with this but obviously it doesn't work:

(defun accum (x &optional (memo (list)))
    (nconc memo (list x)))

CL-USER> (accum 1)
(1)
CL-USER> (accum 2)
(2)


I know that in functional programming the encouraged style is to
create a new value every time but I wonder if there is a way to do an
exact translation (e.g. if performance matters).

Thanks,
George
From: Alessio
Subject: Re: nconc and function parameters [newbie]
Date: 
Message-ID: <e8bc3144-806a-4647-af63-d4526b440058@m34g2000hsb.googlegroups.com>
Actually, to me the Python behaviour seems rather counter-intuitive :)
I guess it depends on the point of view...

Using a bit un-lispy terminology: in Lisp, variables declared within a
function have a scope which is local to that function. So every time
the function is called you get new variables. To have an accumulator
like the one you're describing, you need to declare a variable outside
the function itself:

(let ((acc ())) ;declare a variable, initially nil
  (defun accum (x)
     (setf acc (nconc acc (list x))))) ;let's stick to nconc...

Note that setf returns the new value of acc, and since setf is the
last expression in the function, accum returns that value as well. So,
no longer than the Python version ;)

However, this way you can only have one accumulator; in general you'll
want to have several ones, so you could write an accumulator
generator:

(defun make-accum (&optional acc) ;nil by default
  (lambda (x) ;anonymous function
    (setf acc (nconc acc (list x)))))

And now:

(let ((accum1 (make-accum)))
  (print (funcall accum 1)) ;Prints (1)
  (funcall accum 2))) ;returns (1 2)

(let ((accum2 (make-accum (list 1 2))))
  (print (funcall accum 3)) ;Prints (1 2 3)
  (funcall accum 4))) ;returns (1 2 3 4)

This is because the anonymous function returned by make-accum "closes
over" the acc variable (or, better, binding - see below), so this
variable no longer disappears when make-accum returns, but remains
local to the lambda. This is the magic of lexical closures!

The correct terminology - I hope I get it correctly ;) - would be that
bindings created with let or with the function's lambda list (=
argument list) have lexical scope, unless otherwise declared - special
bindings exist as well, and they have a different behaviour, but let's
ignore them for now...

AS
From: ······@gmail.com
Subject: Re: nconc and function parameters [newbie]
Date: 
Message-ID: <fa463cf2-388e-414f-b423-b0b11dd1a047@f47g2000hsd.googlegroups.com>
I dont know what is happening in python version but i dont like it :)

(defun accum-gen ()
   (let (( l (list)))
       (lambda (x) (setf l (nconc l (list x))))))

(defparameter accum (accum-gen))

(funcall accum 1)
 .. and so on
From: Joost Diepenmaat
Subject: Re: nconc and function parameters [newbie]
Date: 
Message-ID: <87zluyhppd.fsf@zeekat.nl>
George Sakkis <·············@gmail.com> writes:

> On Jan 21, 2:23 pm, Alessio <·············@gmail.com> wrote:
> On to the second pitfall, I was surprised to find out that the empty
> list is a singleton; one can't generate a fresh empty list!

Sure you can.

> CL-USER> (eq (list) ())
> T

This only proves that empty lists are eq

> Regardless of whether this is a conscious decision or a historic
> accident, how can one implement the accumulator idiom, i.e. setting up
> an empty list and appending to it ? For instance I tried to translate
> from Python the following trivial snippet:
>
> def accum(x, memo=[]):
>   memo.append(x)
>   return memo
>
>>>> accum(1)
> [1]
>>>> accum(2)
> [1, 2]

I don't know what's going on there, but it looks to me like the memo
variable/argument is kept across calls. Why that would be so, I have no
clue. For some reason, providing an argument does not replace the memo
variable either.

But then, I could never get the hang of python.

> I came up with this but obviously it doesn't work:
>
> (defun accum (x &optional (memo (list)))
>     (nconc memo (list x)))

As stated above, you cannot count on memo to be anything specific after
you use it in a nconc call. use setf, and a closure to capture it:

(let ((memo nil)) (defun accum (x) (setf memo (nconc memo (list x)))))

Joost.
From: Aurélien Campéas
Subject: Re: nconc and function parameters [newbie]
Date: 
Message-ID: <47950a56$0$30655$426a74cc@news.free.fr>
Joost Diepenmaat a �crit :
> George Sakkis <·············@gmail.com> writes:
> 
>> On Jan 21, 2:23 pm, Alessio <·············@gmail.com> wrote:
>> On to the second pitfall, I was surprised to find out that the empty
>> list is a singleton; one can't generate a fresh empty list!
> 
> Sure you can.
> 
>> CL-USER> (eq (list) ())
>> T
> 
> This only proves that empty lists are eq
> 
>> Regardless of whether this is a conscious decision or a historic
>> accident, how can one implement the accumulator idiom, i.e. setting up
>> an empty list and appending to it ? For instance I tried to translate
>> from Python the following trivial snippet:
>>
>> def accum(x, memo=[]):
>>   memo.append(x)
>>   return memo
>>
>>>>> accum(1)
>> [1]
>>>>> accum(2)
>> [1, 2]
> 
> I don't know what's going on there, but it looks to me like the memo
> variable/argument is kept across calls. 

That's Python behaviour. It is a bit controversial but is likely to stay 
for long, AFAIK.

> Why that would be so, I have no
> clue. For some reason, providing an argument does not replace the memo
> variable either.

Providing what argument ?
Note that I have no idea what this code is supposed to do/illustrate, I 
never write things like that ...

> 
> But then, I could never get the hang of python.

Did you really try ??

> 
>> I came up with this but obviously it doesn't work:
>>
>> (defun accum (x &optional (memo (list)))
>>     (nconc memo (list x)))
> 
> As stated above, you cannot count on memo to be anything specific after
> you use it in a nconc call. use setf, and a closure to capture it:
> 
> (let ((memo nil)) (defun accum (x) (setf memo (nconc memo (list x)))))
> 
> Joost.
From: Joost Diepenmaat
Subject: Re: nconc and function parameters [newbie]
Date: 
Message-ID: <87sl0qho3w.fsf@zeekat.nl>
Aurélien Campéas <·························@free.fr> writes:

> Joost Diepenmaat a écrit :
>> I don't know what's going on there, but it looks to me like the memo
>> variable/argument is kept across calls. 
>
> That's Python behaviour. It is a bit controversial but is likely to
> stay for long, AFAIK.
>
>> Why that would be so, I have no
>> clue. For some reason, providing an argument does not replace the memo
>> variable either.
>
> Providing what argument ?

None, it just confused me more.

> Note that I have no idea what this code is supposed to do/illustrate,
> I never write things like that ...
>
>>
>> But then, I could never get the hang of python.
>
> Did you really try ??

No. I thought the basic concept was OK, but I found the final product
too ugly and confusing without giving me any serious benefit over other
languages I use. And like perl, so ugly doesn't scare me much. :-)

Joost.
From: George Sakkis
Subject: Re: nconc and function parameters [newbie]
Date: 
Message-ID: <af75f88b-cd56-4166-b5b5-5d5540afe232@j20g2000hsi.googlegroups.com>
Thanks everyone, that's a helpful bunch! Now, I knew about setf and it
obviously works for this toy example but it's not a "direct
translation" in the sense that setf rebinds a name to a (potentially
new) object, it doesn't mutate the original object. Given that nconc
ignores empty lists, the overal result seems error-prone to me:

CL-USER> (setf acc ())
NIL
CL-USER> (setf arg (list 1 2 3))
(1 2 3)
CL-USER> (setf acc (nconc acc arg))
(1 2 3)
CL-USER> (setf acc (nconc acc '(a b c)))
(1 2 3 A B C)
CL-USER> arg
(1 2 3 A B C)
CL-USER>

Oops... here I intended to change only acc, not arg!

George
From: Joost Diepenmaat
Subject: Re: nconc and function parameters [newbie]
Date: 
Message-ID: <877ii2olwm.fsf@zeekat.nl>
George Sakkis <·············@gmail.com> writes:

> Thanks everyone, that's a helpful bunch! Now, I knew about setf and it
> obviously works for this toy example but it's not a "direct
> translation" in the sense that setf rebinds a name to a (potentially
> new) object, it doesn't mutate the original object. Given that nconc
> ignores empty lists, the overal result seems error-prone to me:
>
> CL-USER> (setf acc ())
> NIL
> CL-USER> (setf arg (list 1 2 3))
> (1 2 3)
> CL-USER> (setf acc (nconc acc arg))
> (1 2 3)
> CL-USER> (setf acc (nconc acc '(a b c)))
> (1 2 3 A B C)
> CL-USER> arg
> (1 2 3 A B C)
> CL-USER>
>
> Oops... here I intended to change only acc, not arg!

Well you don't want nconc, then. You want append (which is the
non-destructive version of nconc). You seem to still be under some
confusion about what destructive functions do.

Most lisp list functions are intended to work as if they return new
fresh lists. The destructive functions still look like that that, but
they can modify their arguments /in any way they see fit/ unless
documented otherwise. 

To understand more, you may want to take a look here: 
<http://www.gigamonkeys.com/book/they-called-it-lisp-for-a-reason-list-processing.html>

Joost.
From: Joost Diepenmaat
Subject: Re: nconc and function parameters [newbie]
Date: 
Message-ID: <87k5m2hnri.fsf@zeekat.nl>
Joost Diepenmaat <·····@zeekat.nl> writes:

> languages I use. And like perl, so ugly doesn't scare me much. :-)

Before anyone get's offended, that should have read "And I like perl..."

Joost.
From: Peter Hildebrandt
Subject: Re: nconc and function parameters [newbie]
Date: 
Message-ID: <op.t5ar8zowx6i8pv@babyfoot>
On Mon, 21 Jan 2008 21:19:30 +0100, George Sakkis  
<·············@gmail.com> wrote:
> Regardless of whether this is a conscious decision or a historic
> accident, how can one implement the accumulator idiom, i.e. setting up
> an empty list and appending to it ? For instance I tried to translate
> from Python the following trivial snippet:
>
> def accum(x, memo=[]):
>   memo.append(x)
>   return memo
>
>>>> accum(1)
> [1]
>>>> accum(2)
> [1, 2]
>
> I came up with this but obviously it doesn't work:
>
> (defun accum (x &optional (memo (list)))
>     (nconc memo (list x)))

memo is reset to a fresh empty list every time.

> CL-USER> (accum 1)
> (1)
... is (nconc (list) (list 1))

> CL-USER> (accum 2)
> (2)
... ditto

> I know that in functional programming the encouraged style is to
> create a new value every time but I wonder if there is a way to do an
> exact translation (e.g. if performance matters).

Try a closure (hint: look it up!):

CL-USER> (let ((acc nil))
	   (defun accum (x)
	     (setf acc (nconc acc (list x)))))
ACCUM
CL-USER> (accum 1)
(1)
CL-USER> (accum 2)
(1 2)

The "functional" version would be:  replace nconc by append (which in this  
case makes little sense).

Or maybe:

CL-USER> (let ((acc nil))
	   (defun accum2 (x)
	     (setf acc (cons x acc))
	     (reverse acc)))


(time ...) helps you analyze the different versions:

For the original version:

CL-USER> (time (dotimes (i 10000) (accum3 i)))
Evaluation took:
   0.381 seconds of real time
   0.336021 seconds of user run time
   0.008001 seconds of system run time
   0 calls to %EVAL
   0 page faults and
   241,840 bytes consed.

With append:

Evaluation took:
   1.707 seconds of real time
   1.624101 seconds of user run time
   0.032002 seconds of system run time
   [Run times include 0.452 seconds GC run time.]
   0 calls to %EVAL
   0 page faults and
   400,199,912 bytes consed.

With cons/reverse:

Evaluation took:
   1.382 seconds of real time
   1.288081 seconds of user run time
   0.052003 seconds of system run time
   [Run times include 0.328 seconds GC run time.]
   0 calls to %EVAL
   0 page faults and
   400,128,584 bytes consed.

Peter

> Thanks,
> George



-- 
Using Opera's revolutionary e-mail client: http://www.opera.com/mail/
From: Aurélien Campéas
Subject: Re: nconc and function parameters [newbie]
Date: 
Message-ID: <4795074f$0$25892$426a74cc@news.free.fr>
George Sakkis a �crit :
> On Jan 21, 2:23 pm, Alessio <·············@gmail.com> wrote:
> 
>> On 21 Gen, 19:54, George Sakkis <·············@gmail.com> wrote:
>>
>>> Hi everyone,
>>> I've been toying with CL for the last few days after a decade or so I
>>> took a class on it and hated it, but perhaps I can appreciate it more
>>> this time around.
>> 2. moreover, in the code below, you are actually modifying "constant"
>> data (that is, the value '("dummy") - it's not a freshly consed list,
>> but a list embedded in program code!). The consequences of doing that
>> are unspecified, so in general, when you plan to modify a data
>> structure, you should always ensure that it's freshly created. E.g.
>> for lists, use the list function:
>>
>> (defparameter x (list "dummy"))
>>
>> I hope that solves your problem! Happy Lisping,
>> Alessio Stalla
> 
> 
> Great, thanks! I thought (list some items) was equivalent to '(some
> items); now it makes sense.
> 
> On to the second pitfall, I was surprised to find out that the empty
> list is a singleton; one can't generate a fresh empty list!
> 
> CL-USER> (eq (list) ())
> T
> 
> Regardless of whether this is a conscious decision or a historic
> accident, how can one implement the accumulator idiom, i.e. setting up
> an empty list and appending to it ? For instance I tried to translate
> from Python the following trivial snippet:
> 
> def accum(x, memo=[]):
>   memo.append(x)
>   return memo
> 

Python lists are Common Lisp vectors. You should lookup the 
documentation for these. Python's append is vector-push-extend.

>>>> accum(1)
> [1]
>>>> accum(2)
> [1, 2]
> 
> I came up with this but obviously it doesn't work:
> 
> (defun accum (x &optional (memo (list)))
>     (nconc memo (list x)))
> 
> CL-USER> (accum 1)
> (1)
> CL-USER> (accum 2)
> (2)
> 
> 
> I know that in functional programming the encouraged style is to
> create a new value every time but I wonder if there is a way to do an
> exact translation (e.g. if performance matters).

An exact translation (if performance and style matter) will be done with 
what I suggested above. Note that there is nothing specially functional 
in Common Lisp ; I mean, it is only more functional than Python by a 
small margin ... and it encourages efficient programming through the 
(re-)use of appropriate data structures (arrays, hashtables, linked lists).

I'm sure a lot of idioms you know by Python habit will apply nicely in 
Lisp. Don't get sucked into 'list programming' (which Lisp is not 
about). A useful exercice for a Pythonista diving into Lisp might be 
trying to write 'object oriented' programs to get the feel of it.

> 
> Thanks,
> George

(sorry for the horrible phrasing)
From: George Sakkis
Subject: Re: nconc and function parameters [newbie]
Date: 
Message-ID: <34157c4a-b672-48e1-99ce-0786778e67c5@z17g2000hsg.googlegroups.com>
On Jan 21, 3:57 pm, Aurélien Campéas
<·························@free.fr> wrote:
> George Sakkis a écrit :
>
>
>
> > On Jan 21, 2:23 pm, Alessio <·············@gmail.com> wrote:
>
> >> On 21 Gen, 19:54, George Sakkis <·············@gmail.com> wrote:
>
> >>> Hi everyone,
> >>> I've been toying with CL for the last few days after a decade or so I
> >>> took a class on it and hated it, but perhaps I can appreciate it more
> >>> this time around.
> >> 2. moreover, in the code below, you are actually modifying "constant"
> >> data (that is, the value '("dummy") - it's not a freshly consed list,
> >> but a list embedded in program code!). The consequences of doing that
> >> are unspecified, so in general, when you plan to modify a data
> >> structure, you should always ensure that it's freshly created. E.g.
> >> for lists, use the list function:
>
> >> (defparameter x (list "dummy"))
>
> >> I hope that solves your problem! Happy Lisping,
> >> Alessio Stalla
>
> > Great, thanks! I thought (list some items) was equivalent to '(some
> > items); now it makes sense.
>
> > On to the second pitfall, I was surprised to find out that the empty
> > list is a singleton; one can't generate a fresh empty list!
>
> > CL-USER> (eq (list) ())
> > T
>
> > Regardless of whether this is a conscious decision or a historic
> > accident, how can one implement the accumulator idiom, i.e. setting up
> > an empty list and appending to it ? For instance I tried to translate
> > from Python the following trivial snippet:
>
> > def accum(x, memo=[]):
> >   memo.append(x)
> >   return memo
>
> Python lists are Common Lisp vectors. You should lookup the
> documentation for these. Python's append is vector-push-extend.

Ah, this was the missing link. So now that's a closer translation to
the original:

(setf *memo* (make-array 0 :fill-pointer 0 :adjustable t))
(defun accum (x &optional (memo *memo*))
    (vector-push-extend x memo) memo)
CL-USER> (accum 1)
#(1)
CL-USER> (accum 2)
#(1 2)

Which brings me to the next question (the last one for today,
promise): binding of default values for optional/keyword parameters.
It seems CL computes the binding at call time rather than function
definition time like Python. Continuing with the previous example:

(setf *memo* (make-array 0 :fill-pointer 0 :adjustable t))
#()
CL-USER> (accum 3)
#(3)

while the Python version would give (the equivalent of) #(1 2 3).
That's one of the few Python gotchas (e.g. [1]) since more often than
not call-time semantics are appropriate. Assuming though that one
wants definition-time semantics (i.e. freeze the binding of memo to
what *memo* refers to _now_, not when called), how would he do it in
lisp ?

George

[1] http://www.python.org/doc/faq/general/#why-are-default-values-shared-between-objects
From: Alessio
Subject: Re: nconc and function parameters [newbie]
Date: 
Message-ID: <9c1645d9-96e6-4b9c-9ef1-9a5d265a266d@p69g2000hsa.googlegroups.com>
> [snip] Assuming though that one
> wants definition-time semantics (i.e. freeze the binding of memo to
> what *memo* refers to _now_, not when called), how would he do it in
> lisp ?

One possible way to do it is to introduce a new lexical binding:

(let ((memo-now *memo*))
  (defun accum (x &optional (memo nil memo-was-supplied-p))
     (unless memo-was-supplied-p
        (setf memo memo-now))
     :bla-bla-bla))

It may be that the unless... is not needed, and you can just do
&optional (memo memo-now), but I'm not sure - so this version is
longer but I'm certain it does the Right Thing ;)

AS
From: Chris Russell
Subject: Re: nconc and function parameters [newbie]
Date: 
Message-ID: <8bd4eff4-3365-43fd-9758-2543997c10ae@j78g2000hsd.googlegroups.com>
On Jan 21, 11:09 pm, George Sakkis <·············@gmail.com> wrote:

>
> while the Python version would give (the equivalent of) #(1 2 3).
> That's one of the few Python gotchas (e.g. [1]) since more often than
> not call-time semantics are appropriate. Assuming though that one
> wants definition-time semantics (i.e. freeze the binding of memo to
> what *memo* refers to _now_, not when called), how would he do it in
> lisp ?
>
> George
>
Well,
(Let ((memo *memo*))
 (defun acc (..)
...
 (setf memo (...))))

would do it, although as with python objects are passed by reference
so manipulation of the vector *memo* can still affect memo.
To prevent  this from happening use
(Let ((memo (copy-seq *memo*)))
(defun ..))
From: Andreas Davour
Subject: Re: nconc and function parameters [newbie]
Date: 
Message-ID: <cs9k5m2psc8.fsf@Psilocybe.Update.UU.SE>
George Sakkis <·············@gmail.com> writes:

> On Jan 21, 2:23 pm, Alessio <·············@gmail.com> wrote:
>
>> On 21 Gen, 19:54, George Sakkis <·············@gmail.com> wrote:
>>
>> > Hi everyone,
>>
>> > I've been toying with CL for the last few days after a decade or so I
>> > took a class on it and hated it, but perhaps I can appreciate it more
>> > this time around.
>>
>> 2. moreover, in the code below, you are actually modifying "constant"
>> data (that is, the value '("dummy") - it's not a freshly consed list,
>> but a list embedded in program code!). The consequences of doing that
>> are unspecified, so in general, when you plan to modify a data
>> structure, you should always ensure that it's freshly created. E.g.
>> for lists, use the list function:
>>
>> (defparameter x (list "dummy"))
>>
>> I hope that solves your problem! Happy Lisping,
>> Alessio Stalla
>
>
> Great, thanks! I thought (list some items) was equivalent to '(some
> items); now it makes sense.

Stop! Go back and re-read about QUOTE! 

/Andreas

-- 
A: Because it fouls the order in which people normally read text.
Q: Why is top-posting such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
From: ···@telent.net
Subject: Re: nconc and function parameters [newbie]
Date: 
Message-ID: <47954b18$0$8424$db0fefd9@news.zen.co.uk>
Andreas Davour wrote:
> Stop!

Hammertime!
From: Ken Tilton
Subject: Re: nconc and function parameters [newbie]
Date: 
Message-ID: <4794f102$0$6351$607ed4bc@cv.net>
George Sakkis wrote:
> Hi everyone,
> 
> I've been toying with CL for the last few days after a decade or so I
> took a class on it and hated it, but perhaps I can appreciate it more
> this time around. So I'm playing with destructive list operations and
> I stumbled on the following:
> 
> CL-USER> (defparameter x '("dummy"))
> (nconc x '(1 2 3))
> (nconc x '(1 2 3))
> (nconc x '(1 2 3))
> x
> 
> ("dummy" 1 2 3 1 2 3 1 2 3)
> CL-USER>
> 
> So far so good.

I think only because it is interpreted and on each interpret the literal 
'(1 2 3) becomes a fresh cons. In compiled code you are outside the 
bounds of the language when you modify literals such as '(1 2 3), so 
anythin can happen, usually bad.

Try to use (list 1 2 3) for things like this unless you are sure you 
will not be using destructive operations.

btw, introductory texts throw around '(1 2 3) type deals quite a bit 
making noobs think that is how one creates a list. It is convenient, but 
again, to be eschewed in the destructive zone.

kt


  Now I'm trying to do the same but from within a
> function:
> 
> CL-USER> (defun foo (x) (nconc x '(1 2 3)))
> (defparameter x '("dummy"))
> (foo x)
> x
> 
> ("dummy" 1 2 3)
> CL-USER>
> 
> Again, nothing unexpected. But then if I try to call (foo x) a second
> time, it seems it goes into an infinite loop allocating more and more
> memory until I kill it. What's happening ?
> 
> Thanks,
> George

-- 
http://www.theoryyalgebra.com/

"In the morning, hear the Way;
  in the evening, die content!"
                     -- Confucius
From: vanekl
Subject: Re: nconc and function parameters [newbie]
Date: 
Message-ID: <fn2r2u$3ec$2@aioe.org>
George Sakkis wrote:
> Hi everyone,
> 
> I've been toying with CL for the last few days after a decade or so I
> took a class on it and hated it, but perhaps I can appreciate it more
> this time around. So I'm playing with destructive list operations and
> I stumbled on the following:
> 
> CL-USER> (defparameter x '("dummy"))
> (nconc x '(1 2 3))
> (nconc x '(1 2 3))
> (nconc x '(1 2 3))
> x
> 
> ("dummy" 1 2 3 1 2 3 1 2 3)
> CL-USER>
> 
> So far so good. Now I'm trying to do the same but from within a
> function:
> 
> CL-USER> (defun foo (x) (nconc x '(1 2 3)))
> (defparameter x '("dummy"))
> (foo x)
> x
> 
> ("dummy" 1 2 3)
> CL-USER>
> 
> Again, nothing unexpected. But then if I try to call (foo x) a second
> time, it seems it goes into an infinite loop allocating more and more
> memory until I kill it. What's happening ?
> 
> Thanks,
> George

per documentation, http://www.lisp.org/HyperSpec/Body/fun_nconc.html
you are in a loop. You concatenated a list to itself. If you've worked with
pointers before this will make more sense.

  (setq x '(a b c)) =>  (A B C)
  (setq y '(d e f)) =>  (D E F)
  (nconc x y) =>  (A B C D E F)
  x =>  (A B C D E F)

Note, in the example, that the value of x is now different, since its last
cons has been rplacd'd to the value of y. If (nconc x y) were evaluated again,
it would yield a piece of a circular list, whose printed representation would
be (A B C D E F D E F D E F ...), repeating forever;
From: Pascal Costanza
Subject: Re: nconc and function parameters [newbie]
Date: 
Message-ID: <5vkgnjF1lgif8U1@mid.individual.net>
George Sakkis wrote:
> Hi everyone,
> 
> I've been toying with CL for the last few days after a decade or so I
> took a class on it and hated it, but perhaps I can appreciate it more
> this time around. So I'm playing with destructive list operations

Don't do that. There are more interesting things to do first.

For example, check out "Practical Common Lisp" by Peter Seibel.


Pascal

-- 
1st European Lisp Symposium (ELS'08)
http://prog.vub.ac.be/~pcostanza/els08/

My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/
From: Joost Diepenmaat
Subject: Re: nconc and function parameters [newbie]
Date: 
Message-ID: <87odbehnyb.fsf@zeekat.nl>
Pascal Costanza <··@p-cos.net> writes:

> George Sakkis wrote:
> For example, check out "Practical Common Lisp" by Peter Seibel.

Defenitely seconded.

You can read the whole book online too, if you're cheap^W just want to
check it out:

http://www.gigamonkeys.com/book/

Joost.
From: George Sakkis
Subject: Re: nconc and function parameters [newbie]
Date: 
Message-ID: <5c08be68-dfbf-4ad8-8ea6-16f31e409003@s13g2000prd.googlegroups.com>
On Jan 21, 4:24 pm, Joost Diepenmaat <·····@zeekat.nl> wrote:
> Pascal Costanza <····@p-cos.net> writes:
> > George Sakkis wrote:
> > For example, check out "Practical Common Lisp" by Peter Seibel.
>
> Defenitely seconded.
>
> You can read the whole book online too, if you're cheap^W just want to
> check it out:
>
> http://www.gigamonkeys.com/book/
>
> Joost.

Yep, I've been doing this (read the first nine chapters already, great
book) but I also find useful to compare and contrast it with things I
already know and how I would solve the same problem with what I'm most
familiar with (Python in my case).

George