## Tuesday, August 08, 2006

### Eager Comprehensions for Black Belts - 1. Basic Generators

1. Basic Generators

Range generators

A generator binds a variable (or more) to a sequence of values.

The generator :range is used to generate the values of a numerical range. The simplest form is (:range <vars> <stop>) which generates the values 0, 1, ..., <stop>-1.
`    (list-ec (:range i 5)          i)              ; => (0 1 2 3 4)`
The form (:range <vars> <start> <stop>) is used when the
start value is different from 0.
`   (list-ec (:range i 3 7)           i)              ; => (3 4 5 6)`
The form (:range <vars> <start> <stop> <step>) allows other step sizes than +1.
`   (list-ec (:range i 0 8 2)          i)              ; => (0 2 4 6) (list-ec (:range i 0 9 2)          i)              ; => (0 2 4 6 8)`
The generator stops when <stop> is reached or crossed. This rule also applies when the step size is negative:
`   (list-ec (:range i 5 0 -1)          i)                  ; => (5 4 3 2 1)`
Note that :range works for integers only, simple stepping leads to accumulation of rounding errors when using reals. To generate a sequence of reals, use :real-range instead. It calculates the value from the index.
`   (list-ec (:real-range i 0 2 0.5)          i)                       ; => (0.0 0.5 1.0 1.5)`
The special generator : which uses the types of its arguments to dispatch to various generators, uses :range and :real-range when given numerical arguments.
`   (list-ec (: i 5 0 -1)          i)             ; => (5 4 3 2 1) (list-ec (: i 0 2 0.5)          i)             ; => (0.0 0.5 1.0 1.5)`
The dispatch happens at run time, so : is slightly slower than using :range directly.

Element generators

A very common use of generators is to run through the elements of a data structure such as a list, a string or a vector.

The simplest form of :list runs through the elements of a list.
`   (list-ec (:list x '(1 2 3))          (* x 2))                        ; (2 4 6)`
It is possible to run through more than one list at a time:
`   (list-ec (:list x '(1 2) '(3 4) '(5 6))          (* x 2))                        ; => (2 4 6 8 10 12)`
The generators :vector and :string works in the same way, but on vectors and strings.
`   (list-ec (:vector x '#(1 2 3))           x)                            ; => (1 2 3) (list-ec (:string x "abc" "def")          x)                       ; => (#\a #\b #\c #\d #\e #\f)`
The dispatching generators uses :list, :vector and :strings, when the type of its arguments are lists, vectors and strings respectively.
`   (list-ec (: x '(1 2 3))          (* x 2))           ; => (2 4 6)`

Scope of variables bound by a generator

A variable bound by a generator can be used after the closing parenthesis of the generator expression and extends to the end of the comprehension.

Labels: