Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Zero-repetition in LOOP, in CLisp

19 views
Skip to first unread message

gentsquash

unread,
May 19, 2011, 10:43:38 PM5/19/11
to
I preface my questions with the disclaimer that I have not read
the entire LOOP spec, only parts. I'll appreciate if someone can
confirm LOOP's behaviour in CLisp, or in another Common Lisp.

A routine I wrote with LOOP failed when a parameter was zero.
This, when running

shell> clisp -norc # Do not load an init file.

... Welcome to GNU CLISP 2.49 (2010-07-07) ...

Here is an example. Results are shown with "=> RESULT".

[1]> (setq bob 9) => 9

[2]> (loop repeat 0
for E = 7 then bob
finally (return E) ) => NIL

I expected to get 7, since

http://www.ai.mit.edu/projects/iiip/doc/CommonLISP/HyperSpec/Body/sec_6-1-2-1.html

says "... All variables are initialized in the loop prologue. ...
Stepping assignments are made in the loop body before any
other forms are evaluated in the body. "

On the other hand, CLisp doc says, in

http://www.clisp.org/impnotes/loop.html

"6.1.2. ITERATION VARIABLES IN THE LOOP EPILOGUE.
The standard is unambiguous in that the iteration variables
do still exist in the FINALLY clause, but not as to what
values these variables might have."

So I figured that loop [2] was indeed setting E to 7, but E
didn't necessarily need to have that value in the `finally' clause.

================================================================
However, replacing `bob' with `9' /does/ give the result I had
expected:

[3]> (loop repeat 0
for E = 7 then 9
finally (return E) ) => 7

Why does replacing `bob' with `9' make a difference, since each
evaluates to 9?

================================================================
Moreover, this form

[4]> (loop for EXIT = (return F)
for F = 7 then 9 )

returned NIL. But shouldn't both `EXIT' and `F' have values? And
the `return' is not in the `finally' clause. [However, I don't know
if `for' stmts count as part of the `body' the spec refers to.]

Is LOOP behaviour unspecified if a `return' is used in an
iteration clause?

================================================================
I'm also perplexed by this:

[5]> (loop initially (return E)
for E = 7 then 9 ) => 7

So that is what I had expected. But inserting a `repeat' clause
trashes the value:

[6]> (loop initially (return E)
repeat 3
for E = 7 then 9 ) => NIL

Ditto if it is `repeat 0':

[7]> (loop initially (return E)
repeat 0
for E = 7 then 9 ) => NIL

However, interchanging the two iteration clauses recovers the value.

[8]> (loop initially (return E)
for E = 7 then 9
repeat 0 ) => 7


[And same for `repeat 3'.]

Sincerely, -Jonathan LF King,
Math dept, Univ. of Florida

Pascal J. Bourguignon

unread,
May 20, 2011, 12:32:18 AM5/20/11
to
gentsquash <gents...@gmail.com> writes:

> I preface my questions with the disclaimer that I have not read
> the entire LOOP spec, only parts. I'll appreciate if someone can
> confirm LOOP's behaviour in CLisp, or in another Common Lisp.
>
> A routine I wrote with LOOP failed when a parameter was zero.
> This, when running
>
> shell> clisp -norc # Do not load an init file.

I'd add -ansi to ensure clisp respects the ANSI standard.


> ... Welcome to GNU CLISP 2.49 (2010-07-07) ...
>
> Here is an example. Results are shown with "=> RESULT".
>
> [1]> (setq bob 9) => 9

Implementation dependant. Lose this bad habit.
You could write:

(let ((bob 9))
(loop
...))

or:

(loop with bob = 9
...)


> [2]> (loop repeat 0
> for E = 7 then bob
> finally (return E) ) => NIL
>
> I expected to get 7, since
>
> http://www.ai.mit.edu/projects/iiip/doc/CommonLISP/HyperSpec/Body/sec_6-1-2-1.html
>
> says "... All variables are initialized in the loop prologue. ...
> Stepping assignments are made in the loop body before any
> other forms are evaluated in the body. "
>
> On the other hand, CLisp doc says, in
>
> http://www.clisp.org/impnotes/loop.html
>
> "6.1.2. ITERATION VARIABLES IN THE LOOP EPILOGUE.
> The standard is unambiguous in that the iteration variables
> do still exist in the FINALLY clause, but not as to what
> values these variables might have."
>
> So I figured that loop [2] was indeed setting E to 7, but E
> didn't necessarily need to have that value in the `finally' clause.

6.1.2.2 Local Variable Initializations

When a loop form is executed, the local variables are bound and are
initialized to some value. These local variables exist until loop
iteration terminates, at which point they cease to exist.

This allows an implementation to bind and initialize those local
variable using a LET form:

(let (E)
...)

and to use setq for all the other change of binding of these variables.

Hence the NIL value you observe.

> ================================================================
> However, replacing `bob' with `9' /does/ give the result I had
> expected:
>
> [3]> (loop repeat 0
> for E = 7 then 9
> finally (return E) ) => 7
>
> Why does replacing `bob' with `9' make a difference, since each
> evaluates to 9?

Because the standard allows implementations to do whatever they want.

What all this means, is merely that your code is not conforming. Do no
write such forms!

> ================================================================
> Moreover, this form
>
> [4]> (loop for EXIT = (return F)
> for F = 7 then 9 )
>
> returned NIL. But shouldn't both `EXIT' and `F' have values?

1- As per 6.1.2.2 quoted above, both EXIT and F have values. They're
both probably bound to NIL (but could be bound to something else).

2- EXIT is never bound to anything else, since the expression computing
the value to be bound to EXIT never returns.

3- therefore F is never bound to another value either, therefore the
value returned by the loop is implementation dependant.

Again, this code is not conforming.


RETURN is a macro that expands to a RETURN-FROM form. RETURN-FROM is a
special operator that doesn't return. RETURN-FROM transfers the control
to an exit point, instead of returning to the caller.

See section: 5.2 Transfer of Control to an Exit Point


> And the `return' is not in the `finally' clause. [However, I don't know
> if `for' stmts count as part of the `body' the spec refers to.]
>
> Is LOOP behaviour unspecified if a `return' is used in an
> iteration clause?

Not necessarily. You can write conforming loop forms.


> ================================================================
> I'm also perplexed by this:
>
> [5]> (loop initially (return E)
> for E = 7 then 9 ) => 7

Yes, initially clauses are executed before the body, but in any order
with respect to the initializations (only after the definition of the
variables). So all those loops are not conforming.


> So that is what I had expected. But inserting a `repeat' clause
> trashes the value:
>
> [6]> (loop initially (return E)
> repeat 3
> for E = 7 then 9 ) => NIL
>
> Ditto if it is `repeat 0':
>
> [7]> (loop initially (return E)
> repeat 0
> for E = 7 then 9 ) => NIL
>
> However, interchanging the two iteration clauses recovers the value.
>
> [8]> (loop initially (return E)
> for E = 7 then 9
> repeat 0 ) => 7

See: 6.1.7.2 Initial and Final Execution

The initially construct causes the supplied compound-forms to be
evaluated in the loop prologue, which precedes all loop code except
for initial settings supplied by constructs with, for, or as. The
code for any initially clauses is executed in the order in which the
clauses appeared in the loop.

> [And same for `repeat 3'.]

In all cases, referencing the FOR variables in the INITIALLY clause is
non conforming.

You could use a WITH variable instead:

(loop with e = 7
initially (return e)
repeat (random 3)
do (setf e 9))
--> 7 ; conformingly


--
__Pascal Bourguignon__ http://www.informatimago.com/
A bad day in () is better than a good day in {}.

WJ

unread,
May 20, 2011, 1:24:36 AM5/20/11
to
gentsquash wrote:

> However, replacing `bob' with `9' does give the result I had

You are "perplexed". You didn't get what you expected.
And you want to know why.

The answer is that you used LOOP.


Paul Graham:

I consider Loop one of the worst flaws in CL, and an example
to be borne in mind by both macro writers and language designers.


Dan Weinreb, one of the designers of Common Lisp:

... the problem with LOOP was that it turned out to be hard to
predict what it would do, when you started using a lot of
different facets of LOOP all together. This is a serious problem
since the whole idea of LOOP was to let you use many facets
together; if you're not doing that, LOOP is overkill.

Frode V. Fjeld

unread,
May 20, 2011, 3:07:53 AM5/20/11
to
gentsquash <gents...@gmail.com> writes:

> [2]> (loop repeat 0
> for E = 7 then bob
> finally (return E) ) => NIL
>
> I expected to get 7, since

This LOOP form is syntactically wrong, because REPEAT is a MAIN-CLAUSE
that must come after any VARIABLE-CLAUSE such as a FOR-AS-CLAUSE, as per
the CLHS entry for LOOP:

loop [name-clause] {variable-clause}* {main-clause}* => result*

If you move the REPEAT clause after the FOR clause, you'll get the
expected result 7.


I'd wish that LOOP implementations would signal an error in situations
such as this rather than silently produce more-or-less reasonable
results.

--
Frode V. Fjeld

kodifik

unread,
May 20, 2011, 9:32:08 AM5/20/11
to
On May 20, 7:24 am, "WJ" <w_a_x_...@yahoo.com> wrote:
> gentsquash wrote:
> >   I preface my questions with the disclaimer that I have not read
> > the entire LOOP spec, only parts.  I'll appreciate if someone can
> > confirm LOOP's behaviour in CLisp, or in another Common Lisp.
>
> >   A routine I wrote with LOOP failed when a parameter was zero.
> > This, when running
>
> >  shell> clisp -norc        # Do not load an init file.
>
> >         ... Welcome to GNU CLISP 2.49 (2010-07-07) ...
>
> > Here is an example.  Results are shown with "=>  RESULT".
>
> >         [1]> (setq bob 9)               => 9
>
> >         [2]> (loop repeat 0
> >                for E = 7 then bob
> >                finally (return E) )     => NIL
>
> > I expected to get 7, since
>
> >http://www.ai.mit.edu/projects/iiip/doc/CommonLISP/HyperSpec/Body/sec...

Common Lisp "loop" construct is the most comprehensive way of
expressing ideas about loops that any programming language has or has
ever had.
Read the post from Frode V. Fjeld and learn, instead of disqualifying
it as a whole.
Jonathan : I would recommend you "Common Lisp Quick Reference" from
Bert Burgemeister.
http://clqr.berlios.de
since it has a complete diagram of loop.

0 new messages