123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182 |
- FOR is a general iteration construct similar in many ways to the Lisp
- Machine LOOP construct, and the earlier InterLISP CLISP iteration
- construct. FOR, however, is considerably simpler, far more "lispy",
- and somewhat less powerful. FOR is loaded as part of the USEFUL
- package. It is hoped that eventuall the RLISP parser will be modified
- to emit calls on this new FOR macro instead of the old one.
- The arguments to FOR are clauses; each clause is itself a list of a
- keyword and one or more arguments. The clauses may introduce local
- variables, specify return values, have side-effects, when the iteration
- should cease, and so on. Before
- going further, it is probably best to give an example. The following
- function will zip together three lists into a list of three element
- lists.
- (de zip3 (x y z) (for (in u x) (in v y) (in w z) (collect (list u v w))))
- The three IN clauses specify that their first argument should take
- successive elements of the respective lists, and the COLLECT clause specifies
- that the answer should be a list built out of its argument. For
- example, (zip3 '(1 2 3 4) '(a b c d) '(w x y z)) is
- ((1 a w)(2 b x)(3 c y)(4 d z)).
- Following are described all the possible clauses. The first few
- introduce iteration variables. Most of these also give some means of
- indicating when iteration should cease. For example, when a list being
- mapped over by an IN clause is exhausted, iteration must cease. If
- several such clauses are given in FOR expression, iteration will cease
- whenever on of the clauses indicates it should, whether or not the
- other clauses indicate that it should cease.
- (in v1 v2) assigns the variable v1 successive elements of the list v2.
- This may take an additional, optional argument:
- a function to be applied to the extracted element or sublist before
- it is assigned to the variable. The following returns the sum of the
- lengths of all the elements of L. [rather a kludge -- not sure why this
- is here. Perhaps it should come out again.]
- (de SumLengths (L) (for (in N L length) (sum N)))
-
- For example, (SumLengths '((1 2 3 4 5)(a b c)(x y))) is 10.
- (on v1 v2) assigns the varaible v1 successive cdrs of the list v2.
- (from var init final step) is a numeric clause. The variable is first
- assigned init, and then incremented by step until it is larger than
- final. Init, final, and step are optional. Init and step both default
- to 1, and if final is omitted the iteration will continue until
- stopped by some other means. To specify a step with init or final
- omitted, or a final with init omitted place nil (the constant -- it
- cannot be an expression) in the appropriate slot to be omitted.
- Final and step are only evaluated once.
- (for var init next) assigns the variable init first, and subsequently
- the value of the expression next. Init and next may be omitted. Note
- that this is identical to the behaviour of iterators in a DO.
- (with v1 v2 ... vN) introduces N locals, initialized to nil. In
- addition, each vi may also be of the form (var init), in which case it
- will be initialized to init.
- There are two clauses which allow arbitrary code to be executed before
- the first iteration, and after the last. (initially s1 s2 ... sN) will
- cause the si's to be evaluated in the new environment (i.e. with the
- iteration variables bound to their initial values) before the first
- iteration. (finally s1 s2 ... sN) causes the si's to be evaluated just
- before the function returns.
- (do s1 s2 ... sN) causes the si's to be evaluated at each iteration.
- The next few clauses build up return types. Except for the
- RETURNS/RETURNING clause, they may each take an additional argument
- which specifies that instead of returning the appropriate value, it is
- accumulated in the specified variable. For example, an unzipper might
- be defined as
- (de unzip3 (L)
- (for (u in L) (with X Y Z)
- (collect (car U) X)
- (collect (cadr U) Y)
- (collect (caddr U) Z)
- (returns (list X Y Z))))
- This is essentially the opposite of zip3. Given a list of three element
- lists, it unzips them into three lists, and returns a list of those
- three lists. For example, (unzip '((1 a w)(2 b x)(3 c y)(4 d z)))
- is ((1 2 3 4)(a b c d)(w x y z)).
- (returns exp) causes the given expression to be the value of the FOR.
- Returning is synonymous with returns. It may be given additional
- arguments, in which case they are evaluated in order and the value of
- the last is returned (implicit PROGN).
- (collect exp) causes the succesive values of the expression to be
- collected into a list.
- (union exp) is similar, but only adds an element to the list if it is
- not equal to anything already there.
- (conc exp) causes the succesive values to be nconc'd together.
- (join exp) causes them to be appended.
- (count exp) returns the number of times exp was non-nil.
- (sum exp), (product exp), (maximize exp), and (minimize exp) do the obvious.
- Synonyms are summing, maximizing, and minimizing.
- (always exp) will return t if exp is non-nil on each iteration. If exp
- is ever nil, the loop will terminate immediately, no epilogue code,
- such as that introduced by finally will be run, and nil will be
- returned. (never exp) is equivlent to (always (not exp)).
- Explicit tests for the end of the loop may be given using (while exp).
- The loop will terminate if exp becomes nil at the beginning of an
- iteration. (until exp) is equivalent to (while (not exp)).
- Both while and until may be given additional arguments;
- (while e1 e2 ... eN) is equivalent to (while (and e1 e2 ... eN))
- and (until e1 e2 ... eN) is equivalent to (until (or e1 e2 ... eN)).
- (when exp) will cause a jump to the next iteration if exp is nil.
- (unless exp) is equivalent to (when (not exp)).
- Unlike MACLISP and clones' LOOP, FOR does all variable binding/updating
- in parallel. There is a similar macro, FOR*, which does it
- sequentially. All variable binding/updating still preceeds any tests
- or other code. Also note that all WHEN or UNLESS clauses apply to all
- action clauses, not just subsequent ones. This fixed order of
- evaluation makes FOR less powerful than LOOP, but also keeps it
- considerably simpler. The basic order of evaluation is
- 1) bind variables to initial values (computed in the outer environment)
- 2) execute prologue (i.e. INITIALLY clauses)
- 3) while none of the termination conditions are satisfied:
- 4) check conditionalization clauses (WHEN and UNLESS), and start next
- iteration if all are not satisfied.
- 5) perform body, collecting into variables as necessary
- 6) next iteration
- 7) (after a termination condition is satisfied) execute the epilogue (i. e.
- FINALLY clauses)
|