[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: LOOP macros.



    Given (LOOP (INITIAL (v1 e1 inc1) (v2 e2 inc2) ...)  ...), which behaves
    like (DO ((v1 e1 inc1) (v2 e2 inc2) ...)  ...), shouldn't the expanded
    form be

                 (LET ((LOOP-EXIT (LAMBDA () -result code-)))
                 (LABELS ((LOOP-TOP
                           (LAMBDA (v1 v2 ...)
                               ...
                                       -increment and step code-
                                       (LOOP-TOP inc1 inc2 ...))))))
                      -before-code-
                      (LOOP-TOP e1 e2 ...)))))

    That is, LOOP-TOP needs arguments for parallel incrementing.  This
    can't be done with the -increment and step code-.

My main technical objection to this implementation is that the current
values of the step variables are not accessible to the exit clause.  You
could rewrite it so that they are, although getting TC to munge that form
correctly may take some trial and error.

I also have a religous objection:

A FEATURE of LOOP is that all forms are evaluated sequentially, NOT in
parallel.  I like this very much-- I do not recall ever having wished that
the variables or parameters of ANY special form were initialized or updated
in parallel.  For example, I have often wished that LET implemented
sequential assignment.  The only reason I can see for it being parallel is
to allow it to be used reliably within macros.  E.g., if LET were
sequential, then the macro:
    (define-macro (foo a b)
        `(let ((x ,a) (y ,b)) ...))
would generate something equivalent to the following when invoked with
(foo baz x):
        (let ((x baz))
        (let ((y x))
            ...))
which is probably not what you wanted.  Outside of this one glitch, I've
found a sequential LET to be far more useful.  In the case being discussed
here, I could not imagine writing code where I cared whether that the
rebinding of the inci's was parallel or sequential.  But, all of the other
bindings within LOOP are defined to be sequential, so these should be
defined that way too.

    Actually only those variables that are given explicit increment forms
    need be included with LOOP-TOP, so that if we have (INITIAL (v1 e1)
    (v2 e2) ...)  then LOOP-TOP will indeed have no arguments.

So you want sequential initialization, but parallel update?

    While I'm here, a style question.  Why is it better to define the
    LOOP-EXIT separately, rather than with LOOP-TOP in the LABELS?  The
    only difference I can see would be if result-code referred to some
    other function called LOOP-TOP, but problems like that can still arise.

Its not a matter of style-- this compiles without CONSing a closure, while
the LABELS you suggest doesn't in the current, imperfect, TC.  In any case,
I don't think that its very important to worry about style in the code
generated by a macro expansion.

    I vote that AFTER be left in, along with multi-expression RESULTs, so
    that various religious fanatics can take their choice.

I give in.
-------