## Saturday, August 12, 2006

### Eager Comprehensions for Black Belts - 3. Multiple generators (nested loops) and qualifiers (filtering)

3. Multiple Generators (nested loops) and qualifiers (filtering)

Comprehensions allow multiple generators. Consider:
`    (list-ec (: x 2)             (: y 3)             (list x y))   ; =>  ((0 0) (0 1) (0 2)                           ;      (1 0) (1 1) (1 2))`
The inner (last) generator spins faster than the outer generator. Since the scope of variables bound by a generator begins after the generator expression, it is possible to refer to variables bound by previous generators.
`    (list-ec (: x 3)             (: y (+ x 1))             (list x y))     ; => ((0 0)                             ;     (1 0) (1 1)                             ;     (2 0) (2 1) (2 2))`
At this point we are capable of generating loads of values, but sometimes we want to skip some of them.

Consider the problem of finding small integers such that:
`  x^2 + y^2 = z^2 .`
A valid strategy is to let x, y and z run from, say, 1 to 100, and skip the triples which doesn't fulfill the equation. To mimic this strategy we will use qualifiers.

The following qualifiers are available for filtering:
`      (if  <test>)    (not <test>*)    (and <test>*    (or  <test>*)`
[Besides the filtering qualifiers all generators, as well as
(begin <sequence>) and (nested <qualifier>*) are also qualifiers.]
`    (list-ec (: x 1 100)             (: y x 100)             (: z y 100)             (if (= (+ (* x x) (* y y))                    (* z z)))             (list x y z))               ; => ((3 4 5)                                         ;     (5 12 13)                                         ;     (6 8 10)                                         ;     ...                                         ;     (60 63 87)                                         ;     (65 72 97))`
The common cases (if (not <test>)), (if (and <test>*)), and (if (or <test>*)) are abbreviated by (not <test>), (and <test>*), and (or <test>*).
`        (list-ec (: x 1 4)             (: y 1 4)             (not (= x y))             (list x y))    ; => ((1 2) (1 3)                            ;     (2 1) (2 3)                            ;     (3 1) (3 2))`

Labels: