Previous chapter: #28: First, Second, Third are Functions (Change)

Dylan Design Notes

Dylan Design Notes: #29: For Loops (Change)

#29: For Loops (Change)

Version 1, January 1994 Copyright (c) 1993-1994, Apple Computer
This Design Note unifies Dylan's existing iteration constructs, for, for-each, and dotimes, into one general for statement. It also changes the keywords in <range> to be compatible with the numeric clauses in the new for statement.

For statement

Replace the for, for-each, and dotimes macros with the following general iteration construct:

for (clauses [{until | while} end-test])  [Special Form]
        body-forms 
        [finally result-forms] 
end
=> values
for allows any number of clauses. Each clause controls one iteration variable throughout the iteration. The optional end-test controls whether the iteration continues or terminates. It does not control any iteration variables.

The kinds of clauses allowed in a for statement include the following:

Explicit step clauses provide the functionality of the old for statement. The syntax for an explicit step clause is as follows:

{variable | variable :: type} = init-value then next-value
Collection clauses provide the functionality of the old for-each statement. The syntax for a collection clause is as follows:
{variable | variable :: type} in collection
Numeric clauses provide a convenient shorthand for iterating over integers. The syntax for a numeric clause is as follows:
{variable | variable :: type} from start 
        [{to | above | below} bound]
        [by increment]
Iteration with for proceeds through the following steps:
  1. Evaluate the expressions that are evaluated just once, in left to right order as they appear in the for statement.

    For explicit step clauses, these expressions are type and init-value.

    For collection clauses, these expressions are type and collection. If the value of collection is not a collection, signal an error.

    For numeric clauses, these expressions are type, start, bound if it is supplied, and increment if it is supplied. If increment is not supplied, it defaults to 1, or -1 if it is an above clause.

  2. Bind the iteration variables of explicit step and numeric clauses.

    For each explicit step clause, bind variable to the value of init-value. If type is supplied and the value of init-value is not of the specified type, signal an error.

    For each numeric clause, bind variable to the value of start. If type is supplied and the value of start is not of the specified type, signal an error.

  3. Check numeric and collection clauses for exhaustion. If a clause is exhausted, go to step 9.

    A collection clause is exhausted if its collection has no next element. (The first time through, the "next element" is the first, if any.)

    Numeric clauses cannot be exhausted if bound is not supplied. If bound is supplied, the following table gives the conditions for exhaustion:

                       increment >= 0        increment < 0
    
    keyword =  to      variable > bound      variable < bound
    keyword =  above   variable <= bound     variable <= bound
    keyword =  below   variable >= bound     variable >= bound
    

  4. Bind the iteration variables of collection clauses. Fresh bindings are created each time through the iteration.

    For each collection clause, bind variable to the next element of the collection for that clause. If type is supplied and this next element of the collection is not of the specified type, signal an error.

  5. If end-test is supplied, evaluate it. The termination conditions depend on the symbol used to introduce the end-test in the for statement.

    If the value of end-test is false and the symbol is while, go to step 9.

    If the value of end-test is true and the symbol is until, go to step 9.

  6. Execute the body-forms in sequence.

  7. Obtain the next values for explicit step and numeric clauses. Values are obtained in left to right order, in the environment produced by step 6.

    For each explicit step clause, evaluate next-value.

    For each numeric clause, add the values of variable and increment.

  8. Bind the iteration variables of explicit step and numeric clauses to the values obtained in step 7. For each clause, if type is supplied and the next value for that clause is not of the specified type, signal an error. Fresh bindings are created each time through the iteration. After variables are bound, go to step 3.

  9. Evaluate the result-forms in sequence. Bindings created in step 2 and 8 are visible during the execution of result-forms. Bindings created in step 4 (i.e. the iteration variables of collection clauses) are not visible during the execution of result-forms. The values of the last result-form are returned by the for statement. If there are no result-forms, #f is returned.

Range keyword arguments

Remove the up-to and through keyword arguments in range and add three arguments, to, above and below, which constrain the range. to is an inclusive bound, above is an exclusive lower bound and below is an exclusive upper bound. above and below constrain the range independent of the sign of by.

Notes

Major changes between this specification and the Dylan book's iteration constructs:

Various kinds of iteration clauses (general iteration clauses, numeric iteration clauses, and clauses for iterating over collections) are allowed to appear in the same construct.

Since clauses themselves can cause the iteration to terminate (for example, when a collection is exhausted), the end test is moved into the clauses and becomes an optional "termination clause."

Optional result expressions are separated from the end test. They now appear at the end of the construct rather than in the middle.

Types may be declared for iteration variables.

Next chapter: #30: Make Range (Change)