Next: , Up: srfi eager-comp spec   [Index]


2.22.4.1 Comprehensions

Syntax: do-ec qualifier* command

Evaluate the command exactly once for each binding in the sequence defined by the qualifiers. If there are no qualifiers command is evaluated exactly once. The expression is evaluated for its side–effects only. The result of the comprehension is unspecified.

Syntax: list-ec qualifier* expression

The list of values obtained by evaluating expression once for each binding in the sequence defined by the qualifiers. If there are no qualifiers the result is the list with the value of expression.

Syntax: append-ec qualifier* expression

The list obtained by appending all values of expression, which must all be lists. Think of it as:

(apply append (list-ec qualifier* expression))
Syntax: string-ec qualifier* expression

The string of all values of expression. Think of it as:

(list->string (list-ec qualifier* expression))
Syntax: string-append-ec qualifier* expression

The string obtained by appending all values of expression, which must all be strings. Think of it as:

(apply string-append (list-ec qualifier* expression))
Syntax: vector-ec qualifier* expression

The vector of all values of expression. Think of it as:

(list->vector (list-ec qualifier* expression))
Syntax: vector-of-length-ec k qualifier* expression

The vector of all values of expression, of which there must be exactly k. This comprehension behaves like vector-ec but can be implemented more efficiently.

Syntax: sum-ec qualifier* expression

The sum of all values of expression. Think of it as:

(apply + (list-ec qualifier* expression))
Syntax: product-ec qualifier* expression

The product of all values of expression. Think of it as:

(apply * (list-ec qualifier* expression))
Syntax: min-ec qualifier* expression
Syntax: max-ec qualifier* expression

The minimum and maximum of all values of expression. The sequence of values must be non-empty. Think of these as

(apply min (list-ec qualifier* expression))
(apply max (list-ec qualifier* expression))

If you want to return a default value in case the sequence is empty you may want to consider:

(fold3-ec 'infinity qualifier* expression min min)
Syntax: any?-ec qualifier* test

Tests whether any value of test in the sequence of bindings specified by the qualifiers is non–#f. If this is the case, #t is returned, otherwise #f. If there are no bindings at all, in the sequence specified by the qualifiers, then the result is #f. The enumeration of values stops after the first non–#f encountered.

Syntax: every?-ec qualifier* test

Tests whether all values of test are non–#f. If this is the case, #t is returned, otherwise #f. If the sequence is empty the result is #t. Enumeration stops after the first #f.

Syntax: first-ec default qualifier* expression
Syntax: last-ec default qualifier* expression

The first or last value of expression in the sequence of bindings specified by the qualifiers. Before enumeration, the result is initialized with the value of default; so this will be the result if the sequence is empty. Enumeration is terminated in first-ec when the first value has been computed.

Syntax: fold-ec x0 qualifier* expression f2)
Syntax: fold3-ec x0 qualifier* expression f1 f2)

Reduce the sequence x[0], x[1], …, x[n-1] of values obtained by evaluating expression once for each binding as specified by qualifier*. The arguments x0, f2, and f1, all syntactically equivalent to expression, specify the reduction process.

The reduction process for fold-ec is defined as follows. A reduction variable x is initialized to the value of x0, and for each k in {0, ..., n-1} the command:

(set! x (f2 x[k] x))

is evaluated. Finally, x is returned as the value of the comprehension.

The reduction process for fold3-ec is different. If and only if n = 0, i.e. the sequence is empty, then x0 is evaluated and returned as the value of the comprehension. Otherwise, a reduction variable x is initialized to the value of (f1 x[0]), and for each k in {1, ..., n-1} the command:

(set! x (f2 x[k] x))

is evaluated. Finally, x is returned as the value of the comprehension.

As the order of the arguments suggests, x0 is evaluated outside the scope of the qualifiers, whereas the reduction expressions involving f1 and f2 are inside the scope of the qualifiers (so they may depend on any variable introduced by the qualifiers). Note that f2 is evaluated repeatedly, with any side–effect or overhead this might have.

The main purpose of these comprehensions is implementing other comprehensions as special cases. They are generalizations of the procedures fold and reduce in the sense of SRFI-1. (Concerning naming and argument order, please refer to the discussion archive of SRFI-1, in particular the posting [Folds].) Note that fold3-ec is defined such that x0 is only evaluated in case the sequence is empty. This allows raising an error for the empty sequence, as in the example definition of min-ec below.

Application–specific comprehension

An important aspect of this SRFI is a modular mechanism to define application–specific comprehensions. To create a new comprehension a hygienic macro with that name is defined. The macro transforms the new comprehension patterns into instances of do-ec, which is the most fundamental eager comprehension, or any other comprehension already defined. For example, the following code defines list-ec and min-ec in terms of fold-ec and fold3-ec:

(define-syntax list-ec
  (syntax-rules ()
    [(list-ec etc1 etc ...)
     (reverse (fold-ec '() etc1 etc ... cons))]))

(define-syntax min-ec
  (syntax-rules ()
    [(min-ec etc1 etc ...)
     (fold3-ec (min) etc1 etc ... min min)]))

Note that the pattern etc1 ... matches the syntax qualifier* expression without separate access to qualifier* and expression. In order to define a comprehension that does need explicit access to the expression part, the following method is used.

First, all qualifiers are collected into a nested–qualifier, and then the “exactly one qualifier” case is implemented. For illustration, the following code defines fold3-ec in terms of do-ec:

(define-syntax fold3-ec
  (syntax-rules (nested)
    [(fold3-ec x0 (nested q1 ...) q etc1 etc2 etc3 etc ...)
     (fold3-ec x0 (nested q1 ... q) etc1 etc2 etc3 etc ...)]
    [(fold3-ec x0 q1 q2 etc1 etc2 etc3 etc ...)
     (fold3-ec x0 (nested q1 q2) etc1 etc2 etc3 etc ...)]
    [(fold3-ec x0 expression f1 f2)
     (fold3-ec x0 (nested) expression f1 f2)]

    [(fold3-ec x0 qualifier expression f1 f2)
     (let ([result #f]
           [empty  #t])
       (do-ec qualifier
         (let ([value expression]) ; don't duplicate code
           (if empty
               (begin
                 (set! result (f1 value))
                 (set! empty #f))
             (set! result (f2 value result)))))
       (if empty x0 result))]))

Finally, observe that the newly defined fold3-ec comprehension inherits all types of qualifiers supported by do-ec, including all application–specific generators; no further definitions are necessary.


Next: , Up: srfi eager-comp spec   [Index]