Allowing a generator g to accept arguments to "add" items into that generator is still a generator.  The point of accumulator is that you can get the result at once, and you don't need to know the type of the result to use it.

The use case of accumulator I see is a generic gatherer---by passing accumulator, one can parameterize sequence operations.  For example, from an infinite generator of integers (size-gen) and an infinite generator of random items, you can write an infinite generator of random sequences, whose return type can be customized by passing suitable accumulators.

(define (random-sequence make-acc size-gen item-gen)
  (lambda ()
    (let ((acc (make-acc)))
      (let loop ((n (size-gen)))
         (if (zero? n)
            (acc (eof-object))
            (begin (acc (item-gen)) (loop (- n 1))))))))

Suppose (integers-poisson$ L) returns an infinite generator that generates random integers accoring to poisson distribtuion of mean L, and (chars$ CHAR-SET) returns an infinite generator that returns random chars from the given char-set.

(random-sequence string-accumulator (integer-poisson$ 5) (chars$ char-set:ascii))

returns a generator that generates random string.

Gauche's dara.random binary uses similar approach, although it uses classes (the callee can derive accumulator from a class object).  For example: http://practical-scheme.net/gauche/man/?p=sequences-of









On Sat, Oct 14, 2017 at 2:46 AM, Marc Nieper-Wißkirchen <xxxxxx@nieper-wisskirchen.de> wrote:
I am not so much concerned about the usability of the accumulator approach in this SRFI, but more about saying that the SRFI 158 concept of an accumulator is dual to the concept of a generator.

In fact, after some thinking, I have come to the belief that the SRFI 158 generators and accumulators are instances of the same, slightly more general concept.

Consider Python's (or ES6's) generators. Such a generator can both be fed a value, and values can be retrieved from such a generator. Also, such a generator has a return value. In other words, it can act as a SRFI 158 generator and as a SRFI 158 accumulator at the same time. Besides showing the applicability of Python's generator concept, it shows that SRFI 158's generator and accumulator concepts are not dual, but are shadows of the same unified concept.

Thus I would like to propose to extend SRFI 158's concept of a generator so that accumulators fit into the concept as well. Say, if "g" is a generator, invoking "g" with no argument will yield the same value, invoking "g" with one or more arguments, will feed these values into the generator (so that it can act as an accumulator). The only issue is about the return value. SRFI 158 dictates that generators return an eof-object when their states are exhausted. This leaves no room to return a meaningful value (as Python's generators can do so that they can act as accumulators). Another shortcoming is that the protocol of SRFI 158's generators and accumulators does not make it straight-forward to feed multiple values into an accumulator or to yield multiple values from a generator. I am not yet sure how to fix it but I do think that fixing it would make SRFI 158 better fit into Scheme's evaluation model (to which multiple values come naturally).

Marc

John Cowan <xxxxxx@ccil.org> schrieb am Fr., 13. Okt. 2017 um 01:52 Uhr:
Marc Nieper-Wißkirchen scripsit:

Adding duals of generators in form of accumulators is a great idea. However, the accumulator protocol does not look as if it is the right one:

The *protocol* is simply this:  If the argument is not an eof-object, do something with it and return an undefined value.  If the argument is an eof-object, return a value which depends in some way on the previously passed objects.  As I understand you, you are not objecting to this protocol, but to the way in which predefined accumulator constructors are specified.
 
In the current proposal, the accumulator now returns its state, meaning that the producer suddenly becomes concerned with the accumulator's state, not the constructor of the accumulator. This looks wrong.

In an accumulator constructed with make-accumulator, it returns some function of the state rather than the state itself, and the creator gets to specify the function (finalizer).    But in a prespecified constructor, the transformation done is a consequence of the way the constructor is implemented.  For example, the list-accumulator constructor's state is a *reversed* list of objects, and the finalizer is `reverse`.

Now I think your argument is that it is useful to be able to specify in advance, at construction time, whatever further finalization the user desires to have done  I think, however, that this is not necessary.  The continuation of an accumulator call with a normal object is inherently different from the continuation of a call with an eof-object. In fhe first case, the continuation will normally discard the returned value, whereas in the second case the returned value is meaningful to the caller.  

So just as the first thing to be done with a value returned from a generator is to test it with `eof-object?`, so any calls to an accumulator with a normal object will normally appear at a distinct place in the control flow from the final call with an eof-object.  As such, the last call can readily be wrapped in any finalizer that seems desirable without interfering with regular calls.  This eliminates the requirement for a double finalization, one inherent to the constructor and one supplied by the user.

I hope this helps clarify my line of thinking.

-- 
John Cowan          http://vrici.lojban.org/~cowan        xxxxxx@ccil.org
                if if = then then then = else else else = if;

To unsubscribe from this list please go to http://archives.simplelists.com