Next: , Previous: Generalized Drivers, Up: Drivers

2.1.4 Generators

In all of the above clauses, the driver variable is updated on each iteration. Sometimes it is desirable to have greater control over updating. For instance, consider the problem of associating numbers, in increasing order and with no gaps, with the non-`nil` elements of a list. One obvious first pass at writing this is:

```  (iter (for el in list)
(for i upfrom 1)
(if el (collect (cons el i))))
```

But on the list `(a b nil c)` this produces ```((a . 1) (b . 2) (c . 4))``` instead of the desired ```((a . 1) (b . 2) (c . 3))```. The problem is that `i` is incremented each time through the loop, even when `el` is `nil`.

The problem could be solved elegantly if we could step `i` only when we wished to. This can be accomplished for any `iterate` driver by writing `generate` (or its synonym `generating`) instead of `for`. Doing so produces a generator—a driver whose values are yielded explicitly. To obtain the next value of a generator variable v, write `(next `v`)`. The value of a `next` form is the next value of v, as determined by its associated driver clause. `next` also has the side-effect of updating v to that value. If there is no next value, `next` will terminate the loop, just as with a normal driver.

Using generators, we can now write our example like this:

```  (iter (for el in list)
(generate i upfrom 1)
(if el (collect (cons el (next i)))))
```

Now `i` is updated only when `(next i)` is executed, and this occurs only when `el` is non-`nil`.

To better understand the relationship between ordinary drivers and generators, observe that we can rewrite an ordinary driver using its generator form immediately followed by `next`, as this example shows:

```  (iter (generating i from 1 to 10)
(next i)
...)
```

Provided that the loop body contains no `(next i)` forms, this will behave just as if we had written `(for i from 1 to 10)`.

We can still refer to a driver variable v without using `next`; in this case, its value is that given to it by the last evaluation of `(next `v`)`. Before `(next `v`)` has been called the first time, the value of v is undefined.

This semantics is more flexible than one in which v begins the loop bound to its first value and calls of `next` supply subsequent values, because it means the loop will not terminate too soon if the generator's sequence is empty. For instance, consider the following code, which tags non-`nil` elements of a list using a list of tags, and also counts the null elements. (We assume there are at least as many tags as non-`nil` elements.)

```  (let* ((counter 0)
(tagged-list (iter (for el in list)
(generating tag in tag-list)
(if (null el)
(incf counter)
(collect (cons el (next tag)))))))
...)
```

It may be that there are just as many tags as non-null elements of `list`. If all the elements of `list` are null, we still want the counting to proceed, even though `tag-list` is `nil`. If `tag` had to be assigned its first value before the loop begins, we would have had to terminate the loop before the first iteration, since when `tag-list` is `nil`, `tag` has no first value. With the existing semantics, however, ```(next tag)``` will never execute, so the iteration will cover all the elements of `list`.

When the “variable” of a driver clause is actually a destructuring template containing several variables, all the variables are eligible for use with `next`. As before, `(next `v`)` evaluates to v's next value; but the effect is to update all of the template's variables. For instance, the following code will return the list `(a 2 c)`.

```  (iter (generating (key . item) in '((a . 1) (b . 2) (c . 3)))
(collect (next key))
(collect (next item)))
```

Only driver clauses with variables can be made into generators. This includes all clauses mentioned so far except for `repeat`. It does not include `for... previous`, ```for... =```, `for... initially... then` or ```for... first... then``` (see below).