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.

[See also :integers and :char-range]


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:

0 Comments:

Post a Comment

<< Home