[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
2nd generation LOOP macro
- To: Common-Lisp at SU-AI
- Subject: 2nd generation LOOP macro
- From: David A. Moon <MOON at MIT-MC>
- Date: Thu, 26 Aug 1982 22:51:00 -0000
- Reply-to: BUG-LOOP at MIT-ML
Here is an extremely brief summary of the proposed new LOOP design, which
has not yet been finalized. Consult the writeup on LOOP in the Lisp
Machine manual or MIT LCS TM-169 for background information. Constructive
comments are very welcome, but please reply to BUG-LOOP at MIT-ML, not to
(LOOP form form...) repeatedly evaluates the forms.
In general the body of a loop consists of a series of clauses. Each
clause is either: a series of one or more lists, which are forms to be
evaluated for effect, delimited by a symbol or the end of the loop; or
a clause-introducing symbol followed by idiosyncratic syntax for that
kind of clause. Symbols are compared with SAMEPNAMEP. Atoms other than
symbols are in error, except where a clause's idiosyncratic syntax permits.
1. Primary clauses
1.1 Iteration driving clauses
These clauses run a local variable through a series of values and/or
generate a test for when the iteration is complete.
FOR/AS <var> ...
CYCLE <var> ...
I won't go into the full syntax here. Features include: setting
to values before starting/on the first iteration/on iterations after
the first; iterating through list elements/conses; iterating through
sequence elements, forwards or backwards, with or without sequence-type
declaration; iterating through arithmetic progressions. CYCLE reverts
to the beginning of the series when it runs out instead of terminating
It is also possible to control whether or not an end-test is generated
and whether there is a special epilogue only evaluated when an individual
end-test is triggered.
1.2 Prologue and Epilogue
INITIALLY form form... forms to be evaluated before starting, but
after binding local variables.
FINALLY form form... forms to be evaluated after finishing.
DO a sort of semicolon needed in odd situations to terminate a clause,
for example between an INITIALLY clause and body forms when no named
clause (e.g. an iteration-driving clause) intervenes.
We prefer this over parenthesization of clauses because of the
general philosophy that it is more important to make the simple cases
as readable as possible than to make micro-improvements in the
NAMED name Gives the block generated by LOOP a name so that
RETURN-FROM may be used.
This will be changed to conform with whatever is put into Common Lisp
for named PROGs and DOs, if necessary.
2. Relevant special forms
The following special forms are useful inside the body of a LOOP. Note
that they need not appear at top level, but may be nested inside other
Lisp forms, most usefully bindings and conditionals.
(COLLECT <value> [USING <collection-mode>] [INTO <var>] [BACKWARDS]
[FROM <initial-value>] [IF-NONE <expr>] [[TYPE] <type>])
This special form signals an error if not used lexically inside a LOOP.
Each time it is evaluated, <value> is evaluated and accumulated in a way
controlled by <collection-mode>; the default is to form an ordered list.
The accumulated values are returned from the LOOP if it is finished
normally, unless INTO is used to put them into a variable (which gets
bound locally to the LOOP). Certain accumulation modes (boolean AND and
OR) cause immediate termination of the LOOP as soon as the result is known,
when not collecting into a variable.
Collection modes are extensible by the user. A brief summary of predefined
ones includes aggregated boolean tests; lists (both element-by-element and
segment-by-segment); commutative/associative arithmetic operators (plus,
times, max, min, gcd, lcm, count); sets (union, intersection, adjoin);
forming a sequence (array, string).
Multiple COLLECT forms may appear in a single loop; they are checked for
compatibility (the return value cannot both be a list of values and a
sum of numbers, for example).
(RETURN value) returns immediately from a LOOP, as from any other block.
RETURN-FROM works too, of course.
(LOOP-FINISH) terminates the LOOP, executing the epilogue and returning
any value defined by a COLLECT special form.
[Should RESTART be interfaced to LOOP, or only be legal for plain blocks?]
3. Secondary clauses
These clauses are useful abbreviations for things that can also be done
using the primary clauses and Lisp special forms. They exist to make
simple cases more readable. As a matter of style, their use is strongly
discouraged in complex cases, especially those involving complex or
3.1 End tests
WHILE <expr> (IF (NOT <expr>) (LOOP-FINISH))
UNTIL <expr> (IF <expr> (LOOP-FINISH))
WHEN <expr> <clause> The clause is performed conditionally.
IF <expr> <clause> synonymous with WHEN
UNLESS <expr> <clause> opposite of WHEN
AND <clause> May be suffixed to a conditional. These two
ELSE <clause> might be flushed as over-complex.
WITH <var> ... Equivalent to wrapping LET around the LOOP.
This exists to promote readability by decreasing
3.4 Return values
RETURN <expr> synonymous with (RETURN <expr>)
COLLECT ... synonymous with (COLLECT ...)
NCONC ... synonymous with (COLLECT ... USING NCONC)
APPEND, SUM, COUNT, MINIMIZE, etc. are analogous
ALWAYS, NEVER, THEREIS abbreviations for boolean collection
There are ways for users to define new iteration driving clauses which
I will not go into here. The syntax is more flexible than the existing
There are also ways to define new kinds of collection.
The second generation LOOP will accept most first-generation LOOP forms
and execute them in the same way, although this was not a primary goal.
Some complex (and unreadable!) forms will not execute the same way or
will be errors.
We intend to come up with much better examples. Examples are very
important for developing a sense of style, which is really what LOOP
is all about.