[racket] Can't `yield' multiple values when `in-generator' is returned from a function?

From: Greg Hendershott (greghendershott at gmail.com)
Date: Fri Sep 14 09:14:00 EDT 2012

Thank you Matthew. I thought I'd also tried `in-producer' without
success, but I may have made a mistake.

Since I posted, I realized I don't need to use a generator at all, so
I'm not road-blocked.

Speaking of which, I'm curious what are folks' attitudes toward
generators? I ask because I rarely see them used in Racket code I've
perused. Is that just because generators are relatively new? Or is it
because they are convenient but somewhat "heavy" performance-wise?

On Fri, Sep 14, 2012 at 8:53 AM, Matthew Flatt <mflatt at cs.utah.edu> wrote:
> At Fri, 14 Sep 2012 08:20:22 -0400, Greg Hendershott wrote:
>> tl'dr: I can `yield' multiple values when an `in-generator' sequence
>> is used directly in a comprehension, but not when it is returned from
>> a function. I'm stumped.
>>
>>
>> Let's try using the `in-generator' sequence directly in a comprehension:
>>
>> ;; Yield 1 value, directly using `in-generator`
>> (for/list ([x (in-generator (for ([i (in-range 4)])
>>                               (yield i)))])
>>   x)
>> ;; => '(0 1 2 3)
>>
>> ;; Yield 2 values, directly using `in-generator`
>> (for/list ([(x y) (in-generator (for ([i (in-range 4)])
>>                                   (yield i 0)))])
>>   (cons x y))
>> ;; => '((0 . 0) (1 . 0) (2 . 0) (3 . 0))
>>
>> Great!
>>
>> Next, let's try using the `in-generator' sequence as returned from a
>> function. As best I can understand from the docs, this should work. It
>> does for the case of yield-ing 1 value -- but not 2 values:
>>
>> ;; Yield 1 value, using `in-generator' returned from a function:
>> (define (in-gen-1)
>>   (in-generator (for ([i (in-range 4)])
>>                   (yield i))))
>> (for/list ([x (in-gen-1)])
>>   x)
>> ;; => '(0 1 2 3)
>>
>> ;; Yield 2 values, using `in-generator' returned from a function:
>> (define (in-gen-2)
>>   (in-generator (for ([i (in-range 4)])
>>                                   (yield i 0))))
>> (for/list ([(x y) (in-gen-2)])
>>   (cons x y))
>> ;; ==> EXCEPTION:
>> ; .../private/for.rkt:1046:17: arity mismatch;
>> ;  the expected number of arguments does not match the given number
>> ;   expected: 1
>> ;   given: 2
>> ;   arguments...:
>> ;    0
>> ;    0
>>
>> Why?
>
> It's a problem in `in-generator' --- specifically in the way that
> `in-generator' expands to `in-producer' when the `in-generator'
> expression is not in a `for' right-hand side. In that case, the
> `in-generator' expansion doesn't know how many "stop" values it's
> supposed to produce.
>
>
> To work around the problem, you can use `in-producer' and `generator':
>
>  ;; Yield 2 values, using `in-generator' returned from a function:
>  (define (in-gen-2)
>    (in-producer (generator ()
>                            (for ([i (in-range 4)])
>                              (yield i 0))
>                            (values 'done 'done))
>                 (lambda (a b) (eq? a 'done))))
>
>  (for/list ([(x y) (in-gen-2)])
>    (cons x y))
>
>
> I'll work on a repair for `in-generator'.
>

Posted on the users mailing list.