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

2nd generation LOOP macro



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
me personally.

(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.

REPEAT <count>
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
  the iteration.

  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.

1.3 Delimiter

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
	complicated cases.

1.4 Blockname

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
nested conditionals.

3.1 End tests

WHILE <expr>		(IF (NOT <expr>) (LOOP-FINISH))
UNTIL <expr>		(IF <expr> (LOOP-FINISH))

3.2 Conditionals

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.

3.3 Bindings

WITH <var> ...		Equivalent to wrapping LET around the LOOP.
			This exists to promote readability by decreasing
			indentation.

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

4. Extensibility

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
path mechanism.

There are also ways to define new kinds of collection.

5. Compatibility

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.

6. Documentation

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.