Next: loops generators let, Previous: loops generators port, Up: loops generators [Index]

- Generator Syntax:
**:**`vars``arg0``arg`... First the

`arg`expressions are evaluated into*a[1], a[2], …, a[n]*and then a global dispatch procedure is used to dispatch on the number and types of the arguments and run the resulting generator. Initially the following cases are recognized, with*i \in {1, …, n}*:- ‘
`:list`’ If for all

*i*:(list? a[i]) ⇒ #t

- ‘
`:string`’ If for all

*i*:(string? a[i]) ⇒ #t

- ‘
`:vector`’ If for all

*i*:(vector? a[i]) ⇒ #t

- ‘
`:range`’ If

*n \in {1, …, 3}*and for all*i \in {1, …, n}*:(and (integer? a[i]) (exact? a[i])) ⇒ #t

- ‘
`:real-range`’ If

*n \in {1, …, 3}*and for all*i \in {1, …, n}*:(real? a[i]) ⇒ #t

- ‘
`:char-range`’ If

*n = 2*and for all*i \in {1, 2}*:(char? a[i]) ⇒ #t

- ‘
`:port`’ If

*n \in {1, 2}*and:(and (input-port? a[1]) (procedure? a[2])) ⇒ #t

The current dispatcher can be retrieved as

`(:-dispatch-ref)`

, a new dispatcher ‘`d`’ can be installed by`(:-dispatch-set! d)`

yielding an unspecified result, and a copy of the initial dispatcher can be obtained as`(make-initial-:-dispatch)`

. Please refer to the section below for recommendation how to add cases to the dispatcher.- ‘

- Generator Syntax:
**:dispatched**`vars``dispatch``arg0``arg`... Runs the variables through a sequence defined by

`dispatch`and the`arg`expressions. The purpose of ‘`:dispatched`’ is implementing dispatched generators, in particular the predefined dispatching generator ‘`:`’.The working of ‘

`:dispatched`’ is as follows: First`dispatch`and the`arg`expressions are evaluated, resulting in a procedure`d`(the “dispatcher”) and the values*a[1], a[2], …, a[n]*. Then:(d (list a[1] a[2] ... a[n]))

is evaluated, resulting in a value

`g`. If`g`is not a procedure then the dispatcher did not recognize the argument list and an error is raised. Otherwise the “generator procedure”`g`is used to run`vars`through a sequence of values.The sequence defined by

`g`is obtained by repeated evaluation of`(`

until the result is`g``empty`)`empty`. In other words,`g`indicates the end of the sequence by returning its only argument, for which the caller has provided an object distinct from anything`g`can produce.The definition of dispatchers is greatly simplified by the macro

`:generator-proc`

that constructs a generator procedure from a typed generator. Let`(`

be an instance of the`g``var``arg0``arg`...)`?generator`syntax, for example an application–specific typed generator, with a single variable`var`and no index variable. Then:(:generator-proc (g arg0 arg ...)) ⇒ g

where the generator procedure

`g`runs through the list:(list-ec (g var arg0 arg ...) var)

In order to define a new dispatching generator (say

`:my`

) first a dispatching procedure (say`:my-dispatch`

) is defined. The dispatcher will be called with a single (!) argument containing the list of all values to dispatch on. To enable informative error messages, the dispatcher should return a descriptive object (e.g. a symbol for the module name) when it is called with the empty list. Otherwise (if there is at least one value to dispatch on), the dispatcher must either return a generator procedure or`#f`

(which means: no interest). As an example, the following skeleton code defines a dispatcher similar to the initial dispatcher of`:`

:(define (:my-dispatch args) (case (length args) ((1) (let ((a1 (car args))) (cond ((list? a1) (:generator-proc (:list a1))) ((string? a1) (:generator-proc (:string a1))) ...more unary cases... (else #f)))) ((2) (let ((a1 (car args)) (a2 (cadr args))) (cond ((and (list? a1) (list? a2)) (:generator-proc (:list a1 a2))) ...more binary cases... (else #f)))) ...more arity cases... (else (cond ((every?-ec (:list a args) (list? a)) (:generator-proc (:list (apply append args)))) ...more large variable arity cases... (else #f)))))

Once the dispatcher has been defined, the following macro implements the new dispatching generator:

(define-syntax :my (syntax-rules (index) ((:my cc var (index i) arg0 arg ...) (:dispatched cc var (index i) :my-dispatch arg0 arg ...)) ((:my cc var arg0 arg ...) (:dispatched cc var :my-dispatch arg0 arg ...))))

This method of extension yields complete control of the dispatching process. Other modules can only add cases to ‘

`:my`’ if they have access to ‘`:my-dispatch`’.

An alternative to adding a new dispatched generator is to extend the
predefined generator ‘`:`’. Technically, extending ‘`:`’ means
installing a new global dispatching procedure using
‘`:-dispatch-set!`’ as described above. In most cases, however, the
already installed dispatcher should be extended by new cases. The
following procedure is a utility for doing so:

(dispatch-union d1 d2) ⇒ d

where the new dispatcher `d` recognizes the union of the cases
recognized by the dispatchers `d1` and `d2`. The new dispatcher
always tries both component dispatchers and raises an error in case of
conflict. The identification returned by `(d)`

is the
concatenation of the component identifications `(d1)`

and
`(d2)`

, enclosed in lists if necessary. For illustration, consider
the following code:

(define (example-dispatch args) (cond ((null? args) 'example) ((and (= (length args) 1) (symbol? (car args)) ) (:generator-proc (:string (symbol->string (car args))))) (else #f))) (:-dispatch-set! (dispatch-union (:-dispatch-ref) example-dispatch))

After evaluation of this code, the following example will work:

(list-ec (: c 'abc) c) ⇒ (#\a #\b #\c)

Adding cases to ‘`:`’ is particularly useful for frequent cases of
interactive input. Be warned, however, that the advantage of global
extension also carries the danger of conflicts, unexpected
side–effects, and slow dispatching.

Next: loops generators let, Previous: loops generators port, Up: loops generators [Index]