Subject: Re: Misusing LOOP correctly?
From: rpw3@rpw3.org (Rob Warnock)
Date: Mon, 12 Nov 2007 01:25:38 -0600
Newsgroups: comp.lang.lisp
Message-ID: <wpidnUECq-VvYqranZ2dnUVZ_v2pnZ2d@speakeasy.net>
<squash+go@math.ufl.edu> wrote:
+---------------
| rpw3@rpw3.org (Rob Warnock) wrote:
| > If you look carefully at the FOR clauses you have written and
| > consider them in light of CLHS 6.1.1.6 Order of Execution
| > <http://alu.org/HyperSpec/Body/sec_6-1-1-6.html> you should
| > be able to see both why these loops produce the results that
| > they do and why CMUCL is complaining about unreachable code.
| 
| Yes.  Does the LOOP spec allow me to rely on this behavior?
+---------------

In any ANSI-copliant CL, yes.

+---------------
| I understand that LOOP-vars are initialized before the body
| is executed. But is LOOP required to initialize the `for'
| variables in the order listed --and is LOOP forbidden from
| looking-ahead to see that some `for'-clause is vacuous?
+---------------

Yes, and yes:

    http://alu.org/HyperSpec/Body/sec_6-1-2-1.html
    6.1.2.1 Iteration Control
    ...
    The iteration control clauses FOR, AS, and REPEAT must precede
    any other loop clauses, except INITIALLY, WITH, and NAMED, since
    they establish variable bindings. When iteration control clauses
    are used in a loop, the corresponding termination tests in the loop
    body are evaluated before any other loop body code is executed.

    If multiple iteration clauses are used to control iteration,
    variable initialization and stepping occur sequentially by default. 

That is, if you have two FORs, the second is considered to be part
of the loop body of the first, and thus if the first terminates
without ever executing, the initiatialization of the second will
never occur.

But also note:

    The AND construct can be used to connect two or more iteration
    clauses when sequential binding and stepping[1] are not necessary.
    The iteration behavior of clauses joined by AND is analogous to
    the behavior of the macro DO with respect to DO*.

That is, FOR/FOR/FOR/... act like DO*, but FOR/AND/AND/... act like DO.

So if you had used AND instead of the second FOR, the order of the
clauses wouldn't have mattered and you would have *always* gotten
the QUIT-ABRUPTLY return:

    CL-USER(1): (loop for var from 3 upto 2
	              and EXIT = (return 'Quit-Abruptly)
	          finally (return 'Normal-Quit))
    QUIT-ABRUPTLY
    CL-USER(2): (loop for EXIT = (return 'Quit-Abruptly)
	              and var from 3 upto 2
	          finally (return 'Normal-Quit))
    QUIT-ABRUPTLY
    CL-USER(3): 

[Note: AT least, that's what happens on Allegro CL and a really old
version of CLISP. On the other hand, CMUCL-19c still complains about
"Deleting unreachable code" and *always* returns NORMAL-QUIT from
the FOR/AND version, regardless of the order. Some comments would be
appreciated from someone more knowledgeable than I about whether it
is legal for CMUCL to do that or not. I can make an arguement for
both ways.]

+---------------
| In my actual application, the numbers in "for var from 3 upto 2"
| are parameters, but for certain parameter-values, the clause might
| be vacuous.
+---------------

Such as "from 3 upto 2", which executes no body.


-Rob

-----
Rob Warnock			<rpw3@rpw3.org>
627 26th Avenue			<URL:http://rpw3.org/>
San Mateo, CA 94403		(650)572-2607