[racket] taking from a generator, and a possible bug

From: Asumu Takikawa (asumu at ccs.neu.edu)
Date: Sun Aug 19 01:51:17 EDT 2012

On 2012-08-18 21:59:28 -0700, Ian Tegebo wrote:
> (take k (in-generator (infinite-generator (yield (random n)))))
>
> where k and n are positive integers, k<n.
>
> Unfortunately, 'in-generator' returns a sequence while 'take' needs a
> list and calling 'sequence->list' results in an error.

One way to get around this without using the `lazy` language is to use
stream functions. Sequences can be converted to streams, which are
general things that can be `first` and `rest`ed.

Here's a simple implementation of `stream-take`:

    (define (stream-take st n)
      (if (= n 0)
          '()
          (stream-cons (stream-first st)
                       (stream-take (stream-rest st)
                                    (sub1 n)))))

You can use it like this:

    (define st
      (sequence->stream
       ;; in-producer works here. in-generator's body expects
       ;; a yielding expression, not a generator object
       (in-producer
        (infinite-generator
         (yield (random 10)))
        (lambda (x) #f))))

    (stream-take st 10)

This will work, but produces an opaque stream. Use stream accessors or
`stream->list` to get at its elements. This is the best that can be done
with the current stream API because it can't build a stream of the "same
type" right now (e.g., `stream-map` on a list is no longer a list).

I'm not sure if there is a good reason that `stream-take` is not in the
stream library already.

Cheers,
Asumu

Posted on the users mailing list.