Re: LOOP blows!



* Kaz Kylheku Wrote on Thu, 7 Feb 2008 21:03:21 -0800 (PST):

| On Feb 7, 7:38 pm, Madhu
|> If you wanted this to return '(1 2 3) you should have written:
|>
|>  (loop with x = '(1 2 3) for y in x collect y)
|
| But the point is that
|
| (loop for x = '(1 2 3) for y in x collect y)
|
| /does/ return (1 2 3) for me. I suspected that this is the cause of
| the problem, which is why I presented that test case. (Though I
| fumbled with that spurious DO).

This must considered merely to be an artifact of your implementation,
you should not make an inference on how LOOP *should* behave from this
behaviour.

|>  * All variables are initialized first, regardless of where the establishing
|>     clauses appear in the source. The order of initialization follows the
|>     order of these clauses."
|>
|> So X is initialized to NIL before entering entering the first
|> iteration.
|
| Indeed yes, so what?

There are two `initializations' in execution of LOOP, [as I tried to make
clear].

One: INITIALLY. All variables are initialized at the beginning --- but
before staring the first iteration. the INITIALLY clause is executed
after this phase.

Two: At beginning of each iteration. All variables in the FOR clauses
are initialized in this phase.

(loop with x = 10 initially (princ x) repeat 2 do (dummy))
=> prints 10.

(loop for x = 10 initially (princ x) repeat 2 do (dummy))
=> prints NIL

ONLY WITH variables are initialized before start of first iteration. FOR
iterations are bound to NIL.

But this is already clear to you

|> The first for clause will never terminate.  The second for clause
|> terminates when there are no more elements to iterate over, as per
|> 6.1.2.2 above when the list it is iterating over is empty.
|
| X isn't the empty list any longer, because the first clause, FOR X =
| '(1 2 3), assigns a value to X. This clause is not combined with the
| second FOR Y clause using AND, so they do not work in parallel.

I cited the reference to show it is initialized to (1 2 3) ONLY during
the beginning of the first iteration.

But the termination test for the 2nd for loop kicks in BEFORE that!
Which is why the loop is never entered.

| I understand that X is a local variable that starts out NIL. The first
| FOR must change that by giving it a value.
|
| Now, if I had
|
| FOR X = '(1 2 3) AND Y IN X
|
| then you would have a case. Now they are parallel, and so Y iterates
| using the value of X that existed before the assignment of '(1 2 3),
| the initial NIL. Thus the FOR Y IN clause instantly terminates and the
| loop is dead on arrival.

No no no! LOOP FOR X = '(1 2 3) AND Y IN X is just wrong syntax. It is
not allowed by LOOP. your mplementation is horrible if it lets it
through. The two `for' clauses being connected are different. the
second clause is a for-as-in-list clause.

The only reason it would terminate would be the same. INITIALLY: X NIL Y
NIL. The termination test passes, before the first iteration of the
loop (when the for-as-is-clause variable can be initialized) is even
entered.

|> I'd like to emphasise that there is no ambiguity in LOOP, the perceived
|> ambiguity comes from people expecting some behaviour without
|> understanding the well specified execution model.
|
| Right, and ``People'' includes the ones implementing LOOP, apparently,
| which is why we are getting different answers for some perfectly
| innocuous code that ought to be portable.
|
| It looks like LOOP is harder to get right than a lot of other parts of
| Common Lisp! LOOP is historically a source of portability bugs.

That may be a fact, but I think it tells more on the implementors
ability/taste than the standard.

|> PS: If your goal was to return (1 2 3) you should not even start
|> considering this form of LOOP.
|>
|> Even when what you wrote is translated to
|> DO* (do* ((x '(1 2 3) '(1 2 3))
|>        (xtemp x (cdr xtemp))
|>        (y (car x))
|
| This is not how FOR IN works. It captures the value of the list
| expression once, and then steps over /that/ list object, regardless of
| what happens to the value of that original expression.

Yes, My mistake I meant (CAR XTEMP).

| What you want above is:
|
| (Y (CAR XTEMP))
|
| You must use your hidden list iteration variable to set up the
| successive values for Y, not make repeated references to the X
| variable.
|
| The logic you are describing has no hope of working; it's just
| extracting (CAR X) on every iteration, and X doesn't change.
|
|>        (ret))
|>       ((null xtemp) (reverse ret))
|
| See, why are you using the hidden iteration variable XTEMP to figure
| out when the list iteration ends, but using (CAR X) to actually pull
| out the value?
|
| The logic is inconsistent.

But This was not even meant to be an accurate translation of your
[wrong]example. It was meant to illustrate a point. And it is easily
illustrated now :)

You said yourself that Y is meant ``capture the value of the list
expression once, and then step over /that/ list object, regardless of
what happens to the value of that original expression.''

Now, this happens but it happens BEFORE X is initialized to '(1 2 3) in
the for-as-then clause. It HAS to happen then, and not on the first
iteration, [it is this implausibility of this scenario i wished to show
in the DO* example, but no point continuing on a wrong example]
|
| (let ((list '(1 2 3)))
| (loop for x in list collecting x do pop list))
|
| should still produce (1 2 3), even though LIST changes throughout the
| loop. The x variable iterates over the object that was initially
| produced by LIST.

Yes

--
Madhu
.



Relevant Pages