Re: parallel stepping in loop, but what about termination tests?

Pascal Bourguignon <[email protected]>
Newsgroups gmane.lisp.clisp.devel
Message-ID <[email protected]>

> On 24 Nov 2017, at 16:09, <[email protected]> <[email protected]> wrote:
> 
> Hi,
> 
> The following two loops produce identical results and side-effects. Surprise?
> 
> (loop for x across "abc" and for z on (list 1) do (princ x) finally (return (cons x z)))
> (loop for x across "abc"     for z on (list 1) do (princ x) finally (return (cons x z)))
> a
> -> (#\b)
> 
> One *might* have expected "AND", implying parallel stepping, to assign either all values,
> or nothing when iteration terminates. However, in the above case, x clearly has the value
> #\b from a second round, but there's only one iteration -- one would think.

The first form seems to be a syntax error; other implementations signal it:

$ clall -r '(loop for x across "abc" and for z on (list 1) do (princ x) finally (return (cons x z)))' '(loop for x across "abc"     for z on (list 1) do (princ x) finally (return (cons x z)))'

Armed Bear Common Lisp         Z is an unknown keyword in FOR or AS clause in LOOP. Current LOOP context: FOR X ACROSS "abc" AND FOR Z ON (LIST 1).
Armed Bear Common Lisp         --> (#\b)
Clozure Common Lisp            Z is an unknown keyword in FOR or AS clause in LOOP. Current LOOP context: FOR X ACROSS "abc" AND FOR Z ON (LIST 1).
Clozure Common Lisp            --> (#\b)
CLISP                          --> (#\b)
CLISP                          --> (#\b)
ECL                            Z is an unknown keyword in FOR or AS clause in LOOP. Current LOOP context: FOR X ACROSS "abc" AND FOR Z ON (LIST 1).
ECL                            --> (#\b)
SBCL                           Z is an unknown keyword in FOR or AS clause in LOOP. current LOOP context: FOR X ACROSS "abc" AND FOR Z ON (LIST 1).
SBCL                           --> (#\b)


$ clall  '(loop for x across "abc" and z on (list 1) do (princ x) finally (return (cons x z)))' '(loop for x across "abc"  as z on (list 1) do (princ x) finally (return (cons x z)))'



Armed Bear Common Lisp:a
--> (#\b)


Armed Bear Common Lisp:a
--> (#\b)


Clozure Common Lisp:a
--> (#\b)


Clozure Common Lisp:a
--> (#\b)


CLISP:a
--> (#\b)


CLISP:a
--> (#\b)


ECL:a
--> (#\b)


ECL:a
--> (#\b)


SBCL:a
--> (#\b)


SBCL:a
--> (#\b)


Here are the 4 occurrences of the keyword AND in the syntax of LOOP:

with-clause::= with var1 [type-spec] [= form1] {and var2 [type-spec] [= form2]}* 
conditional::= {if | when | unless} form selectable-clause {and selectable-clause}*  
               [else selectable-clause {and selectable-clause}*]  
               [end] 
for-as-clause::= {for | as} for-as-subclause {and for-as-subclause}* 


The semantics of AND vs. FOR|AS are specified in 6.1.2.1:

If multiple iteration clauses are used to control iteration, variable initialization and stepping[1] occur sequentially <http://www.lispworks.com/documentation/HyperSpec/Body/26_glo_s.htm#sequentially> by default. The and construct can be used to connect two or more iteration clauses when sequential <http://www.lispworks.com/documentation/HyperSpec/Body/26_glo_s.htm#sequential> binding <http://www.lispworks.com/documentation/HyperSpec/Body/26_glo_b.htm#binding> and stepping[1] are not necessary. The iteration behavior of clauses joined by and is analogous to the behavior of the macro do <http://www.lispworks.com/documentation/HyperSpec/Body/m_do_do.htm#do>with respect to do* <http://www.lispworks.com/documentation/HyperSpec/Body/m_do_do.htm#doST>.


This means that if you don’t have references to the previous iteration variable in the increment of the current clause, AND will make no different with FOR or AS.  The results above are therefore correct.

One case where it makes a difference is:

$ clall -r  '(loop for x across #((1 2 3) (4 5 6) (7 8 9)) and z := nil :then x finally (return (list :x x :z z)))'

Armed Bear Common Lisp         --> (:X (7 8 9) :Z (4 5 6))
Clozure Common Lisp            --> (:X (7 8 9) :Z (4 5 6))
CLISP                          --> (:X (7 8 9) :Z (7 8 9))
ECL                            --> (:X (7 8 9) :Z (4 5 6))
SBCL                           --> (:X (7 8 9) :Z (4 5 6))

$ clall -r  '(loop for x across #((1 2 3) (4 5 6) (7 8 9)) for z := nil :then x finally (return (list :x x :z z)))'

Armed Bear Common Lisp         --> (:X (7 8 9) :Z (7 8 9))
Clozure Common Lisp            --> (:X (7 8 9) :Z (7 8 9))
CLISP                          --> (:X (7 8 9) :Z (7 8 9))
ECL                            --> (:X (7 8 9) :Z (7 8 9))
SBCL                           --> (:X (7 8 9) :Z (7 8 9))


> This contributes to the topic of non-obvious values of variables within FINALLY clauses.
> 
> So the question IMHO is: when, if ever, shall termination tests be combined, such that
> all tests (from FOR clauses) are performed prior to assigning new values?
> 
> Testing varying inputs with clisp's LOOP macro, I've seen tests sometimes combined,
> others not. The picture is not yet clear to me.
> 
> Combined test & stepping might look like this:
> (when (OR (<= (length vector) index) (atom z)) (LOOP-FINISH))
> (PSETQ x (AREF vector index) z (cdr z))
> 
> ... (INCF index)
> 
> [From an implementation POV, combined tests might require more internal variables
> (cf. e.g. internals of FOR HASH), thus be slower.]
> 
> Regards,
> 	Jörg




-- 
__Pascal J. Bourguignon__

------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot

_______________________________________________
clisp-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/clisp-devel
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.