Lisp HUG Maillist Archive

Is this an expected behavior?

Hi,

I just spent about 30 minutes trying to figure out this behavior before i could find out how to solve it.
This might be an expected behavior (not by me) but if it is maybe someone can explain it to me?

Take this sample code

CL-USER 151 > (defun test ()
                (loop with entries = '(())
                      for entry = (random 4)
                      until (= entry 3)
                      do (setf (first entries)
                               (append (first entries)
                                       (list entry)))
                      finally return entries))
TEST

CL-USER 152 > (test)
(NIL)

CL-USER 153 > (test)
((0 1 0))

CL-USER 154 > (test)
((0 1 0 2))

CL-USER 155 > (test)
((0 1 0 2 0 2 1 1 2 2))

I was expecting the ENTRIES list to be reinitialized with each invocation of TEST but that doesn't seem to be happening, any idea why? I noticed that if I replace the quoted list with (LIST '()) everything works as I expected. This is not specific to the LOOP, if i remove the ENTRIES declaration to a LET form it still behaves the same. Does this have to do with some compilation magic?

Regards,

Alex Paes

Re: Is this an expected behavior?

I believe it is due to the spec:
http://www.lispworks.com/documentation/lw60/CLHS/Body/26_glo_c.htm

constant form n. any form for which evaluation always yields the same value, that neither affects nor is affected by the environment in which it is evaluated (except that it is permitted to refer to the names of constant variables defined in the environment), and that neither affects nor is affected by the state of any object except those objects that are otherwise inaccessible parts of objects created by the form itself. ``A car form in which the argument is a quote form is a constant form.''

I found some discussion on it here:
http://stackoverflow.com/questions/134887/when-to-use-quote-in-lisp

On Fri, Mar 26, 2010 at 9:24 PM, Alexandre Paes <alex.paes@streetdogstudio.com> wrote:
Hi,

I just spent about 30 minutes trying to figure out this behavior before i could find out how to solve it.
This might be an expected behavior (not by me) but if it is maybe someone can explain it to me?

Take this sample code

CL-USER 151 > (defun test ()
                (loop with entries = '(())
                      for entry = (random 4)
                      until (= entry 3)
                      do (setf (first entries)
                               (append (first entries)
                                       (list entry)))
                      finally return entries))
TEST

CL-USER 152 > (test)
(NIL)

CL-USER 153 > (test)
((0 1 0))

CL-USER 154 > (test)
((0 1 0 2))

CL-USER 155 > (test)
((0 1 0 2 0 2 1 1 2 2))

I was expecting the ENTRIES list to be reinitialized with each invocation of TEST but that doesn't seem to be happening, any idea why? I noticed that if I replace the quoted list with (LIST '()) everything works as I expected. This is not specific to the LOOP, if i remove the ENTRIES declaration to a LET form it still behaves the same. Does this have to do with some compilation magic?

Regards,

Alex Paes

Re: Is this an expected behavior?

Take this sample code

CL-USER 151 > (defun test ()
                (loop with entries = '(())
                      for entry = (random 4)
                      until (= entry 3)
                      do (setf (first entries)
                               (append (first entries)
                                       (list entry)))
                      finally return entries))

I'd do this:

(defun test2 ()
  (list
   (loop for entry = (random 4)
         until (= entry 3)
         collect entry)))

Re: Is this an expected behavior?


Am 27.03.2010 um 03:24 schrieb Alexandre Paes:

> Hi,
> 
> I just spent about 30 minutes trying to figure out this behavior before i could find out how to solve it.
> This might be an expected behavior (not by me) but if it is maybe someone can explain it to me?
> 
> Take this sample code
> 
> CL-USER 151 > (defun test ()
>                 (loop with entries = '(())
>                       for entry = (random 4)
>                       until (= entry 3)
>                       do (setf (first entries)
>                                (append (first entries)
>                                        (list entry)))
>                       finally return entries))

Let me mention a few problems I see with your code:

1)  '(()) this is a constant form that is not portably meant to be modified.
     Here, if you use it, all invocations of TEST will use the same data.

2) APPEND should not be done there, LOOP can collect values.
    Appending to the end of a list in a LOOP is not efficient.

3) Your code:

     FINALLY RETURN entries

    violates the standard LOOP syntax. Use instead

      FINALLY (return entries)

Regards,

Rainer Joswig

> TEST
> 
> CL-USER 152 > (test)
> (NIL)
> 
> CL-USER 153 > (test)
> ((0 1 0))
> 
> CL-USER 154 > (test)
> ((0 1 0 2))
> 
> CL-USER 155 > (test)
> ((0 1 0 2 0 2 1 1 2 2))
> 
> I was expecting the ENTRIES list to be reinitialized with each invocation of TEST but that doesn't seem to be happening, any idea why? I noticed that if I replace the quoted list with (LIST '()) everything works as I expected. This is not specific to the LOOP, if i remove the ENTRIES declaration to a LET form it still behaves the same. Does this have to do with some compilation magic?
> 
> Regards,
> 
> Alex Paes

Rainer Joswig, Hamburg, Germany
http://lispm.dyndns.org/
mailto:joswig@lisp.de




Re: Is this an expected behavior?

Hi everyone,

Thank you all for you help, i'm perfectly aware of the COLLECT available in the LOOP construct, i was just modifying some code that i found on the web and came across this behavior.

So, if i'm understanding this correctly, whenever i need to modify a list i should *never* use a quoted list?

Re: Is this an expected behavior?

it is undefined to modify any literal constant. i.e.
'(a b c d)
#(1 2 3 4 5)
"a string"

regards,

Ala'a (cmo-0)


Updated at: 2020-12-10 08:39 UTC