[plt-scheme] srfi-42, values, named let, etc.

From: Jens Axel Søgaard (jensaxel at soegaard.net)
Date: Sat Sep 22 18:01:16 EDT 2007

Hi David,

> Is there some way of modifying it so that it plays nice with
> :parallel?  Alternatively, is there some way of modifying :parallel so
> that it plays nice with the above ?

Tough questions. My first thought is that the problem might be
rooted in the definition of :parallel :

   (:parallel <generator>*)
       Runs several generators in parallel. This means that the next
   binding in the sequence is obtained by advancing each generator in
   <generator>* by one step. The parallel generator terminates when any
   of its component generators terminates. The generators share a common
   scope for the variables they introduce. This implies that the names of
   the variables introduced by the various generators must be distinct.

The part that troubles me is the: "The generators share a common
scope for the variables they introduce."

If I recall correctly, my first implementation gave each generator
its own scope. Whether it was accident or whether I just thought
it was the most natural, I don't remember.

In fact the following test exposes whether or not the introduced
variables share scope

      (list-ec (:parallel (:integers x)
                          (:do ((i 10)) (< x i) ((- i 1))))
               (list x i))
      => '((0 10) (1 9) (2 8) (3 7) (4 6)) )

This relates to your G) which asked why the following
expressions didn't return the same result:

(let ([a 1][b 1])
    (list-ec (:do ((a 0)) (< a 10) ((+ a b))) a)
    (list-ec (:do ((b 0)) (< b 10) ((+ a b))) b)))

(let ([a 1][b 1])
   (list-ec (:parallel
             (:do ((a 0)) (< a 10) ((+ a b)))
             (:do ((b 0)) (< b 10) ((+ a b)))) (list a b)))

[NB: The last expressions crashes DrScheme, if no memory limit is set!]

It seems to me that both types of :parallel (with and without shared
scope of introduced variables) are useful. If normal naming were used,
they ought to be called :parallel (separate scope) and :parallel-rec
(shared scope), but since the one with shared scope is named :parallel
in SRFI42, we need another name. In lieu of a better name I'll
call it :parallel-sep.

The definition of :parallel is given by the following - the
interesting clause is the one with two generators:

(define-generator (:parallel form-stx)
     ; TODO: Check that all subforms are generators
     (syntax-case form-stx (index)
       [(_ (index i) q ...)
        (add-index form-stx #'(_ q ...) #'i)]
       [(_ gen)
        (generator->loop #'gen)]
       [(_ gen1 gen2)
        (syntax-case (list (loop-stx (generator->loop #'gen1))
                           (loop-stx (generator->loop #'gen2))) ()
          [(((ob ...) (oc ...) (lb ...) ne1
             (ib ...) (ic ...) ne2 (ls ...))
            ((ob2 ...) (oc2 ...) (lb2 ...) ne12
             (ib2 ...) (ic2 ...) ne22 (ls2 ...)))
            #'((ob ... ob2 ...)
               (oc ... oc2 ...)  (lb ... lb2 ...)
               (and ne1 ne12)    (ib ... ib2 ...)
               (ic ... ic2 ...) (and ne2 ne22)
               (ls ... ls2 ...)))])]
       [(_ gen1 gen2 gen3 ...)
        #'(:parallel (:parallel gen1 gen2) gen3 ...)]))

As can be seen the outer bindings (ob ...) and (ob2 ...)
are merged into (ob ... ob2 ...) which means that get to
share scope.

To define a :parallel-sep we can introduce a marker,
and use it to mark everything that stem from the
second generator. One way to introduce a new mark
is to use make-syntax-introducer to make a syntax-marker
with a fresh mark.

Are you interested in giving it a go?

Jens Axel Søgaard

Posted on the users mailing list.