From: Bruno Haible
Subject: CLtL2 LOOP semantics
Date: 
Message-ID: <1v76kt$b54@nz12.rz.uni-karlsruhe.de>
The description of the CLtL2 LOOP macro in CLtL2 and the ANSI draft seems
self-contradictory.

1. The first paragraph on p. 710 suggests that the loop variables are
   bound once and assigned a value once per iteration, just like DO or DO*
   does. In the description of FOR .. IN and FOR .. ON (p. 720, 721),
   however, the wording is:
   "The variable var is bound to the successive elements of the list
    before each iteration."
   "The variable var is bound to the successive tails of the list."

   As a test case, what's the result of
   (mapcar #'funcall (loop for x in '(a b c) collect #'(lambda () x))) ?

2. What's the scope of the loop variables? This is explained for WITH
   clauses (p.737), but not for loop variables introduced by FOR/AS clauses.

   Test cases:
   (let ((x 'a) (y 'b))
     (loop repeat 2 for x = 1 then 2 for y = x collect (list x y)))
   (let ((x 'a) (y 'b))
     (loop repeat 2 for x = 1 then 2 and y = x collect (list x y)))

3. Consider the following test case.

   (let ((x '(99)) (y 42))
     (loop for x in '()
           for y = (first x)
           initially (print y)
   ) )

   What does it print?

   p.710 specifies that the termination test is executed in the loop body,
   not in the loop prologue. Since the INITIALLY code is part of the loop
   prologue (p.711), it is executed exactly once. p.711 also says that
   the initialization of x occurs before the initialization of y. So
   x ought to be initialized in the loop prologue. (This interferes with
   the first question.) But the first time x gets a value is the first
   iteration, isn't it?


How is the specification to be interpreted?


                    Bruno Haible
                    ······@ma2s2.mathematik.uni-karlsruhe.de

From: Barry Margolin
Subject: Re: CLtL2 LOOP semantics
Date: 
Message-ID: <1v7q7tINNat5@early-bird.think.com>
In article <··········@nz12.rz.uni-karlsruhe.de> ······@ma2s2.uucp (Bruno Haible) writes:
>The description of the CLtL2 LOOP macro in CLtL2 and the ANSI draft seems
>self-contradictory.

There are quite a few problems with the LOOP description.  Some of them
were cleaned up in the dpANS.  Some things have been cleared up since then,
but it's still pretty messy.

>1. The first paragraph on p. 710 suggests that the loop variables are
>   bound once and assigned a value once per iteration, just like DO or DO*
>   does. In the description of FOR .. IN and FOR .. ON (p. 720, 721),
>   however, the wording is:
>   "The variable var is bound to the successive elements of the list
>    before each iteration."
>   "The variable var is bound to the successive tails of the list."

Section 6.1.2.6 of the dpANS draft 12.24 (the version that went out for
public review) says that iteration variables are "stepped", and the
glossary definition of "step" says that it's an assignment, not a new
binding.  It has the same text as you quoted in the descriptions of
FOR-AS-IN-LIST and FOR-AS-ON-LIST.  However, the word "bound" is ambiguous
in this context; it can either be the past tense of "to bind", which
implies that it creates a new binding, or the adjective that means that it
has a denotation in a binding.  Since the first definition would make the
standard inconsistent, it must be rejected; the second definition is
consistent, so it can be used.

>2. What's the scope of the loop variables? This is explained for WITH
>   clauses (p.737), but not for loop variables introduced by FOR/AS clauses.

This is answered in section 6.1.2.2 of the dpANS:

    Implementations can interleave the setting of initial values with the
    \term{bindings}.  However, the assignment of the initial values is
    always calculated in the order specified by the user.  A variable is
    thus sometimes bound to a meaningless value of the correct \term{type},
    and then later in the prologue it is set to the true initial value by
    using \specref{setq}.  One implication of this interleaving is that it
    is \term{implementation-dependent} whether the \term{lexical
    environment} in which the initial value \term{forms} (variously called
    the \param{form1}, \param{form2}, \param{form3}, \param{step-fun},
    \param{vector}, \param{hash-table}, and \param{package}) in any
    \param{for-as-subclause}, except \param{for-as-equals-then}, are
    \term{evaluated} includes only the loop variables preceding that
    \term{form} or includes more or all of the loop variables; the
    \param{form1} and \param{form2} in a \param{for-as-equals-then} form
    includes the \term{lexical environment} of all the loop variables.

>   Test cases:
>   (let ((x 'a) (y 'b))
>     (loop repeat 2 for x = 1 then 2 for y = x collect (list x y)))
>   (let ((x 'a) (y 'b))
>     (loop repeat 2 for x = 1 then 2 and y = x collect (list x y)))

The first must return ((1 1) (2 2))' the lack of an AND connective implies
that Y is assigned the value of X after X has been initialized or stepped.

The second can return ((1 <anything>) (2 1)); it returns ((1 1) (2 1)) on
my Lisp Machine when I use LISP:LOOP, and ((1 NIL) (2 1)) when I use
FUTURE-COMMON-LISP:LOOP.  This is a case of the variable being "bound to a
meaningless value ... and then later in the prologue it is is set".  So,
the variable X is initially bound to a meaningless value, and it is this
value that can be used when Y is initialized.

>3. Consider the following test case.
>
>   (let ((x '(99)) (y 42))
>     (loop for x in '()
>           for y = (first x)
>           initially (print y)
>   ) )
>
>   What does it print?
>
>   p.710 specifies that the termination test is executed in the loop body,
>   not in the loop prologue. Since the INITIALLY code is part of the loop
>   prologue (p.711), it is executed exactly once. p.711 also says that
>   the initialization of x occurs before the initialization of y. So
>   x ought to be initialized in the loop prologue. (This interferes with
>   the first question.) But the first time x gets a value is the first
>   iteration, isn't it?

Stuff like this was brought up by public review comments.  I'm not sure
what the state of clarification is.  We may not be able to resolve all the
ambiguities and inconsistency.

I think this is another case where X and Y are bound to an arbitrary value
in the prologue, and then assigned at the beginning of each iteration.  The
INITIALLY clause will print the arbitrary value that Y was bound to.  I
just tried this on my Lispm:

(loop for x in '((1))
      for y = (first x)
      initially (print y))

and it printed NIL.

I believe there are some committee members trying to clear up various
problems with the iteration clauses that step through data types like lists
and arrays.  They're different from the arithmetic iteration clauses
because there's a "hidden" variable that the actual end test operates on,
and the specification of the semantics of iteration doesn't say how the
hidden variable fits in.  I think they're trying to clarify this.

>How is the specification to be interpreted?

If you're a user, as strictly as possible. :-) Basically, if it's not clear
how something should be interpreted, don't do it, since it's possible that
an implementor and you disagree on the interpretation.  So if you can't
figure out how to do something with LOOP, don't use it; there are plenty of
other iteration constructs with much simpler semantics.

If you're an implementor, do your best and pray.

Hopefully the next draft of the standard should be a little better, but I
don't think it will fix all the problems (I think about 20% of the public
review comments were about LOOP).  I know this is a cop-out, but we live in
the real world, and if we wait until we've fixed all the problems with LOOP
before we adopt the standard it will be too late (some people think it's
already too late).

-- 
Barry Margolin
System Manager, Thinking Machines Corp.

······@think.com          {uunet,harvard}!think!barmar
From: Mike Haynie
Subject: Re: CLtL2 LOOP semantics
Date: 
Message-ID: <MBH.93Jun11084701@wisdom.wisdom.attmail.com>
In article <··········@nz12.rz.uni-karlsruhe.de> ······@ma2s2.uucp (Bruno Haible) writes:

Here's my interpretation;

   The description of the CLtL2 LOOP macro in CLtL2 and the ANSI draft seems
   self-contradictory.

   1. The first paragraph on p. 710 suggests that the loop variables are
      bound once and assigned a value once per iteration, just like DO or DO*
      does. In the description of FOR .. IN and FOR .. ON (p. 720, 721),
      however, the wording is:
      "The variable var is bound to the successive elements of the list
       before each iteration."
      "The variable var is bound to the successive tails of the list."

      As a test case, what's the result of
      (mapcar #'funcall (loop for x in '(a b c) collect #'(lambda () x))) ?

The result of the loop will be a series of functions, each of which
have a pointer to a binding of X. I believe that in most (if not all)
implementations, each of the closures will point to the *same*
binding. Therefore, the result will be '(c c c).

I recall a discussion within the last six months on this topic for do
and do*. It appears that some implementations will come up with '(a b
c). 

   2. What's the scope of the loop variables? This is explained for WITH
      clauses (p.737), but not for loop variables introduced by FOR/AS clauses.

      Test cases:
      (let ((x 'a) (y 'b))
	(loop repeat 2 for x = 1 then 2 for y = x collect (list x y)))
      (let ((x 'a) (y 'b))
	(loop repeat 2 for x = 1 then 2 and y = x collect (list x y)))

I'll punt on this; anyone?

   3. Consider the following test case.

      (let ((x '(99)) (y 42))
	(loop for x in '()
	      for y = (first x)
	      initially (print y)
      ) )

      What does it print?

Actually, I think that the initially clause is misplaced (?). Isn't
there a paragraph specifying the order of the various types of
clauses? I recall that the intially clauses must come before any
iteration clauses...

      p.710 specifies that the termination test is executed in the loop body,
      not in the loop prologue. Since the INITIALLY code is part of the loop
      prologue (p.711), it is executed exactly once. p.711 also says that
      the initialization of x occurs before the initialization of y. So
      x ought to be initialized in the loop prologue. (This interferes with
      the first question.) But the first time x gets a value is the first
      iteration, isn't it?


   How is the specification to be interpreted?


		       Bruno Haible
		       ······@ma2s2.mathematik.uni-karlsruhe.de

 Hope this helps.

--

                                ____/|
Michael Haynie                  \ o.O|   ACK!
···@wisdom.attmail.com           =(_)=  THPHTH!
                                   U