From: Mirko
Subject: (let (a bunch of lists) (nconc the same lists)) -- is there a better 	way
Date: 
Message-ID: <9fc21b76-f141-4f38-a003-998a912de45f@s21g2000vbb.googlegroups.com>
Hi,

Consider the following code:

(let ((a '(1 2 3))
      (b '(10 11 12))
      (c '(101 102 103)))
  (print (progn
	   (when t (nconc a b))
	   (when t (nconc a c))
	   a)))

This throws a warning in SBCL about modifying a constant variable.

The (when t ...) actually tests for a keyword value.


Two questions:
 - Can I use some kind of declaration to eliminate the warning
(presumably I know what I'm doing, ahem)
 - What is a better idiom for building a list out of sublists
depending on some conditions?

Thanks,

Mirko

From: blandest
Subject: Re: (let (a bunch of lists) (nconc the same lists)) -- is there a 	better way
Date: 
Message-ID: <397e6966-3503-4cf1-8d24-87b871500af2@w40g2000yqd.googlegroups.com>
On May 29, 4:45 pm, Mirko <·············@gmail.com> wrote:
> Hi,
>
> Consider the following code:
>
> (let ((a '(1 2 3))
>       (b '(10 11 12))
>       (c '(101 102 103)))
>   (print (progn
>            (when t (nconc a b))
>            (when t (nconc a c))
>            a)))
>
> This throws a warning in SBCL about modifying a constant variable.
>
> The (when t ...) actually tests for a keyword value.
>
> Two questions:
>  - Can I use some kind of declaration to eliminate the warning
> (presumably I know what I'm doing, ahem)
>  - What is a better idiom for building a list out of sublists
> depending on some conditions?
>
> Thanks,
>
> Mirko

You are trying to modify a constant list: '(1 2 3). Change it with a
call to #'list.
You could lose the "progn" because it is not needed. Also, the last
#'print may be removed because the return value (local variable a) is
returned from the let form and its value will be printed at the REPL.

(let ((a (list 1 2 3))
      (b (list 10 11 12))
      (c (list 101 102 103)))
  (when t (nconc a b))
  (when t (nconc a c))
  a)

Now try this:

(let ((a (list 1 2 3))
      (b (list 10 11 12))
      (c (list 101 102 103)))
  (print (append a b c))
  (print (nconc a b c))
  (list a b c)

#'append is not destructive, but #'nconc is. You can see that the
result (lists a, b and c) may be modified during the #'nconc
operation.
From: Mirko
Subject: Re: (let (a bunch of lists) (nconc the same lists)) -- is there a 	better way
Date: 
Message-ID: <aa82df47-2df4-4444-8af5-fadd2e12db5e@n8g2000vbb.googlegroups.com>
On May 29, 9:45 am, Mirko <·············@gmail.com> wrote:
> Hi,
>
> Consider the following code:
>
> (let ((a '(1 2 3))
>       (b '(10 11 12))
>       (c '(101 102 103)))
>   (print (progn
>            (when t (nconc a b))
>            (when t (nconc a c))
>            a)))
>
> This throws a warning in SBCL about modifying a constant variable.
>
> The (when t ...) actually tests for a keyword value.
>
> Two questions:
>  - Can I use some kind of declaration to eliminate the warning
> (presumably I know what I'm doing, ahem)
>  - What is a better idiom for building a list out of sublists
> depending on some conditions?
>
> Thanks,
>
> Mirko

First, thanks to Thomas and blandest.  Their solutions worked.  I did
not appreciate the difference between '(...) and (list ...), but I'll
read up on it.

Second, I really should have listned to the compiler warning.  The
code went into an infinite loop (that list was part of a (loop for i
in a ...)

Thanks again,

Mirko
From: gugamilare
Subject: Re: (let (a bunch of lists) (nconc the same lists)) -- is there a 	better way
Date: 
Message-ID: <828dcc91-840f-4903-bf50-55db1e687922@n8g2000vbb.googlegroups.com>
On 29 maio, 11:23, Mirko <·············@gmail.com> wrote:
> First, thanks to Thomas and blandest.  Their solutions worked.  I did
> not appreciate the difference between '(...) and (list ...), but I'll
> read up on it.

The difference is when those lists are constructed. If you write

'(1 2 3)

then this list is made during compile-time (actually during read-
time). This can save time on execution, possibly among other things.
However, modifying it will make the changes permanent and will
probably introduce bugs in your code.

On the other hand, when you write

(list 1 2 3)

then the list is constructed during run-time through an explicit call
to the function list.

In practice:

CL-USER> (defun foo ()
	   '(1 2 3))
FOO
CL-USER> (eq (foo) (foo))
T
CL-USER> (defun bar ()
	   (list 1 2 3))
BAR
CL-USER> (eq (bar) (bar))
NIL
CL-USER> (setf (car (foo)) 5) ; Oops! That is not good!
5
CL-USER> (foo)
(5 2 3)
CL-USER> (setf (car (bar)) 5) ; No problem here...
5
CL-USER> (bar)
(1 2 3)
From: Pascal J. Bourguignon
Subject: Re: (let (a bunch of lists) (nconc the same lists)) -- is there a  better way
Date: 
Message-ID: <7ck53zrkjz.fsf@pbourguignon.anevia.com>
gugamilare <··········@gmail.com> writes:

> On 29 maio, 11:23, Mirko <·············@gmail.com> wrote:
>> First, thanks to Thomas and blandest. �Their solutions worked. �I did
>> not appreciate the difference between '(...) and (list ...), but I'll
>> read up on it.
>
> The difference is when those lists are constructed. If you write
>
> '(1 2 3)
>
> then this list is made during compile-time (actually during read-
> time). This can save time on execution, possibly among other things.
> However, modifying it will make the changes permanent and will
> probably introduce bugs in your code.
>
> On the other hand, when you write
>
> (list 1 2 3)
>
> then the list is constructed during run-time through an explicit call
> to the function list.


There's also another difference:

'(1 ... n)     can be any size as long as there's enough memory.

(list 1 ... n) is limited by call-arguments-limit, which may be as
               small as 50 (but happily is often larger).


> CL-USER> (defun foo ()
> 	   '(1 2 3))
> FOO
> CL-USER> (setf (car (foo)) 5) ; Oops! That is not good!
> 5

Anything can happen here. You could have an error signaled, or something else.

> CL-USER> (foo)
> (5 2 3)

Possibly.  Or (1 2 3) if the quoted data was placed into ROM, or something else.

-- 
__Pascal Bourguignon__
From: gugamilare
Subject: Re: (let (a bunch of lists) (nconc the same lists)) -- is there a 	better way
Date: 
Message-ID: <735ddfb7-c519-4518-a54a-6e5d1899ee1d@n21g2000vba.googlegroups.com>
On 29 maio, 12:33, ····@informatimago.com (Pascal J. Bourguignon)
wrote:
> gugamilare <··········@gmail.com> writes:
> > On 29 maio, 11:23, Mirko <·············@gmail.com> wrote:
> >> First, thanks to Thomas and blandest.  Their solutions worked.  I did
> >> not appreciate the difference between '(...) and (list ...), but I'll
> >> read up on it.
>
> > The difference is when those lists are constructed. If you write
>
> > '(1 2 3)
>
> > then this list is made during compile-time (actually during read-
> > time). This can save time on execution, possibly among other things.
> > However, modifying it will make the changes permanent and will
> > probably introduce bugs in your code.
>
> > On the other hand, when you write
>
> > (list 1 2 3)
>
> > then the list is constructed during run-time through an explicit call
> > to the function list.
>
> There's also another difference:
>
> '(1 ... n)     can be any size as long as there's enough memory.
>
> (list 1 ... n) is limited by call-arguments-limit, which may be as
>                small as 50 (but happily is often larger).

Hum, you are right, good call. Just for reference:

CL-USER> call-arguments-limit ; SBCL
1152921504606846975

[1]> call-arguments-limit ; Clisp
4096

> > CL-USER> (defun foo ()
> >       '(1 2 3))
> > FOO
> > CL-USER> (setf (car (foo)) 5) ; Oops! That is not good!
> > 5
>
> Anything can happen here. You could have an error signaled, or something else.

Oh, yes, you are right. One more reason for not doing this :)

> [...]
From: Barry Margolin
Subject: Re: (let (a bunch of lists) (nconc the same lists)) -- is there a  better way
Date: 
Message-ID: <barmar-843E38.22053129052009@mara100-84.onlink.net>
In article <··············@wyoming.home>,
 Paul Foley <···@below.invalid> (http://public.xdi.org/=pf) wrote:

> ···@informatimago.com (Pascal J. Bourguignon) writes:
> 
> >> CL-USER> (defun foo ()
> >> 	   '(1 2 3))
> >> FOO
> >> CL-USER> (setf (car (foo)) 5) ; Oops! That is not good!
> >> 5
> >
> > Anything can happen here. You could have an error signaled, or something 
> > else.
> 
> No; the only thing that can happen is that the list is changed to (5 2 3).

The spec says that the consequences are undefined if you attempt to 
modify literal data.  So as far as the language definition is concerned, 
anything is permitted.

What you say is most likely, but there's no guarantee.

> 
> >> CL-USER> (foo)
> >> (5 2 3)
> >
> > Possibly.  Or (1 2 3) if the quoted data was placed into ROM, or something 
> > else.
> 
> Then your implementation is broken :)
> 
> If he file-compiled it, the quoted data may be in read-only memory
> and/or shared with other similar lists, but he's typing it at the
> REPL.  In no case could it return (1 2 3) [unless it was in read-only
> memory /and/ the attempt to write to it was silently ignored...]

There's nothing prohibiting the REPL to be implemented as follows: If 
the expression is a definition, write the expression to a temporary 
file, call COMPILE-FILE on the file, then call LOAD on the resulting 
binary.

-- 
Barry Margolin, ······@alum.mit.edu
Arlington, MA
*** PLEASE post questions in newsgroups, not directly to me ***
*** PLEASE don't copy me on replies, I'll read them in the group ***
From: Raffael Cavallaro
Subject: Re: (let (a bunch of lists) (nconc the same lists)) -- is there a  better way
Date: 
Message-ID: <gvq7ib$gqm$1@news.eternal-september.org>
On 2009-05-29 22:30:14 -0400, Paul Foley <···@below.invalid> 
(http://public.xdi.org/=pf) said:

> But the language semantics guarantee it.

I think you're misunderstanding what "undefined" means.

From the hyperspec:
"The consequences are undefined

    This means that the consequences are unpredictable. The 
consequences may range from harmless to fatal. No conforming code may 
depend on the results or effects."

and reflect on the fact that "unpredictable from the language 
semantics" is a proper subset of "unpredictable." IOW, undefined 
behavior is not predictable from the language semantics.

Raffael Cavallaro
From: Kenneth Tilton
Subject: Re: (let (a bunch of lists) (nconc the same lists)) -- is there a  better way
Date: 
Message-ID: <4a20c052$0$5914$607ed4bc@cv.net>
Raffael Cavallaro wrote:
> On 2009-05-29 22:30:14 -0400, Paul Foley <···@below.invalid> 
> (http://public.xdi.org/=pf) said:
> 
>> But the language semantics guarantee it.
> 
> I think you're misunderstanding what "undefined" means.

Which is hard to understand given that the metaspec is so clear on this: 
noses, demons, and flying.

hth,kzo
From: Kaz Kylheku
Subject: Re: (let (a bunch of lists) (nconc the same lists)) -- is there a  better way
Date: 
Message-ID: <20090611121758.907@gmail.com>
On 2009-05-30, Raffael Cavallaro <················@pas.espam.s.il.vous.plait.mac.com> wrote:
> On 2009-05-29 22:30:14 -0400, Paul Foley <···@below.invalid> 
> (http://public.xdi.org/=pf) said:
>
>> But the language semantics guarantee it.
>
> I think you're misunderstanding what "undefined" means.
>
> From the hyperspec:
> "The consequences are undefined
>
>     This means that the consequences are unpredictable. The 
> consequences may range from harmless to fatal. No conforming code may 
> depend on the results or effects."

I believe that the consequences are well-defined, but only for
code entered in the REPL, or dynamically constucted and passed
to EVAL and COMPILE. This is given by the first sentence
in 3.2.4:

  The functions eval and compile are required to ensure that literal objects
  referenced within the resulting interpreted or compiled code objects are the
  same as the corresponding objects in the source code. 

However, the next sentence takes it all away, with respect
to file compilation:

  compile-file, on the other hand, must produce a compiled file that, when
  loaded with load, constructs the objects defined by the source code and
  produces references to them. 

The behavior of self-modifying code is left undefined for the sake of
flexibilities in implementing the file compilation model.

Under file compilation, a lot more is allowed. The compiler may 
aggressively fold common substructures in different instances
of literals to result in smaller object code. The loader may
allocate literals in read-only storage.

So, we can't use REPL examples when arguing for the undefinedness of literal
modifications. It's perfectly fine for interactive experimentation; just a very
bad idea for building an actual program from source files.
From: Kaz Kylheku
Subject: Re: (let (a bunch of lists) (nconc the same lists)) -- is there a  better way
Date: 
Message-ID: <20090612055441.547@gmail.com>
On 2009-05-30, Kaz Kylheku <········@gmail.com> wrote:
> On 2009-05-30, Raffael Cavallaro <················@pas.espam.s.il.vous.plait.mac.com> wrote:
>> On 2009-05-29 22:30:14 -0400, Paul Foley <···@below.invalid> 
>> (http://public.xdi.org/=pf) said:
>>
>>> But the language semantics guarantee it.
>>
>> I think you're misunderstanding what "undefined" means.
>>
>> From the hyperspec:
>> "The consequences are undefined
>>
>>     This means that the consequences are unpredictable. The 
>> consequences may range from harmless to fatal. No conforming code may 
>> depend on the results or effects."
>
> I believe that the consequences are well-defined, but only for
> code entered in the REPL, or dynamically constucted and passed
> to EVAL and COMPILE. This is given by the first sentence
> in 3.2.4:
>
>   The functions eval and compile are required to ensure that literal objects
>   referenced within the resulting interpreted or compiled code objects are the
>   same as the corresponding objects in the source code. 

Err, but wait. Suppose you are compiling code like this:

  `(...  (let* ((a ',list)
                (b (car a)))
    ...))

This is in a template used to make a closure which is then
compiled with COMPILE.

Now suppose that after compiling this function, we modify the list which was
inserted into the code as a quoted literal with ,list

3.2.4 tells us that the variable A should follow this change, since the object
in the compiled function is the same as the one in the source. A is bound to
the same list, and so if we get the function to regurgitate the value of A,
that value of A will be EQ to the original list.

However, what about derived values like B?

Surely the compiler may optimize the code, so that B is replaced by the value
pulled from the list at compile time. And this means that B may or may not
follow the change to the CAR of A.

The undefined behavior of modifying literals allows this.

So according to 3.2.4 we may safely change the object; it isn't write-protected
or anything.

However, after we do that, we don't know what the behavior will be if we call
the function, unless the function doesn't actually access any parts of the list
that we modified, constraining itself only to handling only the leading cons
cell of that list without looking at it.

To require the behavior to work in such cases would reduce opportunities for
access optimization related to literals.

So what 3.2.4 gives us isn't all that useful. We can compile code and then
muck with literals that we inserted into the code, provided that the code
treats the literals completely opaquely---it only replays these literals
(returns them or passes them to other functions) without accessing any of
their constituent parts, since any such accesses could be subject to
constant-folding optimizations.
From: Pascal J. Bourguignon
Subject: Re: (let (a bunch of lists) (nconc the same lists)) -- is there a  better way
Date: 
Message-ID: <878wkf47oz.fsf@galatea.local>
Paul Foley <···@below.invalid> (http://public.xdi.org/=pf) writes:

> Barry Margolin <······@alum.mit.edu> writes:
>
>> In article <··············@wyoming.home>,
>>  Paul Foley <···@below.invalid> (http://public.xdi.org/=pf) wrote:
>>
>>> ···@informatimago.com (Pascal J. Bourguignon) writes:
>>> 
>>> >> CL-USER> (defun foo ()
>>> >> 	   '(1 2 3))
>>> >> FOO
>>> >> CL-USER> (setf (car (foo)) 5) ; Oops! That is not good!
>>> >> 5
>>> >
>>> > Anything can happen here. You could have an error signaled, or something 
>>> > else.
>>> 
>>> No; the only thing that can happen is that the list is changed to (5 2 3).
>>
>> The spec says that the consequences are undefined if you attempt to 
>> modify literal data.  So as far as the language definition is concerned, 
>> anything is permitted.
>>
>> What you say is most likely, but there's no guarantee.
>
> But the language semantics guarantee it.  The list returned by FOO
> must be EQ to the list constructed when the definition of FOO was read
> in, and there's no way to tell the difference between that list and
> any other (e.g., constructed with LIST rather than a literal).

There's no implementation independant way defined by the standard to
tell the difference, but there may be implementation dependent ways to
do so.


> The  meaning of (setf (car <list>) ...) is fixed, so the only thing
> it can possibly do is alter the CAR of that list.

No, the meaning of (setf (car <list>) ...) is undefined, when <list> is a literal.

http://www.lispworks.com/documentation/HyperSpec/Body/s_quote.htm

    The consequences are undefined if literal objects (including
    quoted objects) are destructively modified. 



>>> >> CL-USER> (foo)
>>> >> (5 2 3)
>>> >
>>> > Possibly.  Or (1 2 3) if the quoted data was placed into ROM, or something 
>>> > else.
>>> 
>>> Then your implementation is broken :)
>>> 
>>> If he file-compiled it, the quoted data may be in read-only memory
>>> and/or shared with other similar lists, but he's typing it at the
>>> REPL.  In no case could it return (1 2 3) [unless it was in read-only
>>> memory /and/ the attempt to write to it was silently ignored...]
>>
>> There's nothing prohibiting the REPL to be implemented as follows: If 
>> the expression is a definition, write the expression to a temporary 
>> file, call COMPILE-FILE on the file, then call LOAD on the resulting 
>> binary.
>
> Oh, I think there is: you'd lose identity.

Identity is (eq (foo) (foo)), 
not (eq (foo) (bar)) with:
(defun foo () '(1 2 3))
(defun bar () '(1 2 3)) 

(with compile-file, it could be that (eq (foo) (bar)), but not in the
above implementation of a REPL, since each of foo and bar would be
compiled separately).

-- 
__Pascal Bourguignon__
From: gugamilare
Subject: Re: (let (a bunch of lists) (nconc the same lists)) -- is there a 	better way
Date: 
Message-ID: <290685b0-aa89-46df-9059-61899005c7c4@g19g2000vbi.googlegroups.com>
On 30 maio, 00:41, Paul Foley <····@below.invalid> (http://
public.xdi.org/=pf) wrote:
> ····@informatimago.com (Pascal J. Bourguignon) writes:
> > There's no implementation independant way defined by the standard to
> > tell the difference, but there may be implementation dependent ways to
> > do so.
>
> Think about how to implement it for a while!

Maybe some hypothetical implementation which aims for full safety may
add a "modifiable-p" flag to every object, and both rplaca and rplacd
throw an error if this flag is set. In this implementation, maybe you
can even create unmodifiable objects so that you can create purely
functional code like clojure. Or maybe this implementation separates
the RAM memory into modifiable and unmodifiable data (maybe a lisp
machine).

Anyway, this is not so important. The important lesson here is that
modifying literals is not reliable and shouldn't be done (unless you
_really_ know what you are doing).
From: gugamilare
Subject: Re: (let (a bunch of lists) (nconc the same lists)) -- is there a 	better way
Date: 
Message-ID: <aa0a43e4-c807-44af-a62b-84f23349fb6d@s21g2000vbb.googlegroups.com>
On 30 maio, 01:24, Paul Foley <····@below.invalid> (http://
public.xdi.org/=pf) wrote:
> gugamilare <··········@gmail.com> writes:
> > On 30 maio, 00:41, Paul Foley <····@below.invalid> (http://
> > public.xdi.org/=pf) wrote:
> >> ····@informatimago.com (Pascal J. Bourguignon) writes:
> >> > There's no implementation independant way defined by the standard to
> >> > tell the difference, but there may be implementation dependent ways to
> >> > do so.
>
> >> Think about how to implement it for a while!
>
> > Maybe some hypothetical implementation which aims for full safety may
> > add a "modifiable-p" flag to every object, and both rplaca and rplacd
> > throw an error if this flag is set.
>
> And it knows when to set the flag...how, exactly?

I don't know, after the eval hits the quote special operator? Or,
after it reads, it marks all conses that were read as unmodifiable? It
may be tricky, but I think it is possible.
From: Kaz Kylheku
Subject: Re: (let (a bunch of lists) (nconc the same lists)) -- is there a  better way
Date: 
Message-ID: <20090612054810.456@gmail.com>
On 2009-05-30, gugamilare <··········@gmail.com> wrote:
> On 30 maio, 01:24, Paul Foley <····@below.invalid> (http://
> public.xdi.org/=pf) wrote:
>> gugamilare <··········@gmail.com> writes:
>> > On 30 maio, 00:41, Paul Foley <····@below.invalid> (http://
>> > public.xdi.org/=pf) wrote:
>> >> ····@informatimago.com (Pascal J. Bourguignon) writes:
>> >> > There's no implementation independant way defined by the standard to
>> >> > tell the difference, but there may be implementation dependent ways to
>> >> > do so.
>>
>> >> Think about how to implement it for a while!
>>
>> > Maybe some hypothetical implementation which aims for full safety may
>> > add a "modifiable-p" flag to every object, and both rplaca and rplacd
>> > throw an error if this flag is set.
>>
>> And it knows when to set the flag...how, exactly?
>
> I don't know, after the eval hits the quote special operator? Or,
> after it reads, it marks all conses that were read as unmodifiable? It
> may be tricky, but I think it is possible.

The reader cannot do this, because it is understood to be constructing
a modifiable list. Lisp programs can recover a structure from printed
text and then mutate it. There is nothing wrong with

  (rplaca (read-from-string "(1 2 3)") 5)

The reader is understood to have consed up an ordinary list.

The aforementioned flag could, however, be set by the file compiler and loader,
however.

Restrictions w.r.t. literals clearly exist for the sake of freedoms in
implementing object files, and compiled Lisp executables.
From: Kenneth Tilton
Subject: Re: (let (a bunch of lists) (nconc the same lists)) -- is there a  better way
Date: 
Message-ID: <4a2009e0$0$5911$607ed4bc@cv.net>
Mirko wrote:
> On May 29, 9:45 am, Mirko <·············@gmail.com> wrote:
>> Hi,
>>
>> Consider the following code:
>>
>> (let ((a '(1 2 3))
>>       (b '(10 11 12))
>>       (c '(101 102 103)))
>>   (print (progn
>>            (when t (nconc a b))
>>            (when t (nconc a c))
>>            a)))
>>
>> This throws a warning in SBCL about modifying a constant variable.
>>
>> The (when t ...) actually tests for a keyword value.
>>
>> Two questions:
>>  - Can I use some kind of declaration to eliminate the warning
>> (presumably I know what I'm doing, ahem)
>>  - What is a better idiom for building a list out of sublists
>> depending on some conditions?
>>
>> Thanks,
>>
>> Mirko
> 
> First, thanks to Thomas and blandest.  Their solutions worked.  I did
> not appreciate the difference between '(...) and (list ...), but I'll
> read up on it.
> 
> Second, I really should have listned to the compiler warning.

The meta-lesson here is that Lisp is a lot different than many languages 
in that error messages do tend to tell you what went wrong, so (yes) 
read them and think about them before dashing off to some other theory.

kt
From: Mirko
Subject: Re: (let (a bunch of lists) (nconc the same lists)) -- is there a 	better way
Date: 
Message-ID: <48dd6f50-b49a-4573-9207-c0f182c1daa8@s20g2000vbp.googlegroups.com>
On May 29, 12:14 pm, Kenneth Tilton <·········@gmail.com> wrote:
> Mirko wrote:
> > On May 29, 9:45 am, Mirko <·············@gmail.com> wrote:
> >> Hi,
>
> >> Consider the following code:
>
> >> (let ((a '(1 2 3))
> >>       (b '(10 11 12))
> >>       (c '(101 102 103)))
> >>   (print (progn
> >>            (when t (nconc a b))
> >>            (when t (nconc a c))
> >>            a)))
>
> >> This throws a warning in SBCL about modifying a constant variable.
>
> >> The (when t ...) actually tests for a keyword value.
>
> >> Two questions:
> >>  - Can I use some kind of declaration to eliminate the warning
> >> (presumably I know what I'm doing, ahem)
> >>  - What is a better idiom for building a list out of sublists
> >> depending on some conditions?
>
> >> Thanks,
>
> >> Mirko
>
> > First, thanks to Thomas and blandest.  Their solutions worked.  I did
> > not appreciate the difference between '(...) and (list ...), but I'll
> > read up on it.
>
> > Second, I really should have listned to the compiler warning.
>
> The meta-lesson here is that Lisp is a lot different than many languages
> in that error messages do tend to tell you what went wrong, so (yes)
> read them and think about them before dashing off to some other theory.
>
> kt

No.  The metalesson is that when I think I know what I'm doing, it
should raise a big fat red flag :-)  I should have posted that
question under a different guise.  When my other half finds out about
this, I won't hear the end of it :-)
From: Thomas M. Hermann
Subject: Re: (let (a bunch of lists) (nconc the same lists)) -- is there a better  way
Date: 
Message-ID: <gvoplk$a80$1@news.eternal-september.org>
Mirko wrote:
> Hi,
> 
> Consider the following code:
> 
> (let ((a '(1 2 3))
>       (b '(10 11 12))
>       (c '(101 102 103)))
>   (print (progn
> 	   (when t (nconc a b))
> 	   (when t (nconc a c))
> 	   a)))
> 
> This throws a warning in SBCL about modifying a constant variable.
> 
> The (when t ...) actually tests for a keyword value.
> 
> 
> Two questions:
>  - Can I use some kind of declaration to eliminate the warning
> (presumably I know what I'm doing, ahem)
>  - What is a better idiom for building a list out of sublists
> depending on some conditions?
> 
> Thanks,
> 
> Mirko

How about the simple solution, don't use destructive functions on
constant data.

(let ((a (list 1 2 3))
      (b (list 10 11 12))
      (c (list 101 102 103)))
  (print (progn
          (when t (nconc a b))
          (when t (nconc a c))
          a)))

Hope that helps,

Tom