The generator function can now be used to send values to the generator.
For example, (define g (generator (yield (yield (yield 1))))) (list (g) (g 2) (g 3) (g 4) (g) (g)) evaluates to '(1 2 3 4 4 4). This is something that Python does (as a generator.send method), which might be useful for using generators as co-routines, and it is actually easy to implement since sending values is exactly what we get when the generator call is actually calling the saved continuation. So most of the change is dealing with the technicalities of throwing an error when the generator is called with some arguments, when that's done after it's terminated (at the stage where it's repeating the last value for ever). A few tests added for this. svn: r17979
This commit is contained in:
parent
18c8e41fac
commit
505034ea26
|
@ -51,24 +51,33 @@
|
||||||
|
|
||||||
(define-syntax-rule (generator body0 body ...)
|
(define-syntax-rule (generator body0 body ...)
|
||||||
(let ()
|
(let ()
|
||||||
(define (cont)
|
(define cont
|
||||||
|
(case-lambda
|
||||||
|
[()
|
||||||
(define (yielder value)
|
(define (yielder value)
|
||||||
(shift-at yield-tag k (set! cont k) value))
|
(shift-at yield-tag k (set! cont k) value))
|
||||||
(reset-at yield-tag
|
(reset-at yield-tag
|
||||||
(parameterize ([current-yielder yielder])
|
(parameterize ([current-yielder yielder])
|
||||||
|
(define ret
|
||||||
(call-with-values
|
(call-with-values
|
||||||
(lambda () (begin body0 body ...))
|
(lambda () (begin body0 body ...))
|
||||||
;; only a normal return gets here
|
;; get here only on at the end of the generator
|
||||||
(case-lambda
|
(case-lambda
|
||||||
;; Note: in this case, the generator was invoked with no
|
;; Note: in this case, the generator was invoked with no
|
||||||
;; arguments, so returning no values is more symmetric. But
|
;; arguments, so returning no values is more symmetric.
|
||||||
;; this is a common case, and probably people would expect a
|
;; But this is a common case, and probably people would
|
||||||
;; void result more than no values.
|
;; expect a void result more than no values.
|
||||||
[() (set! cont void)]
|
[() void]
|
||||||
[(r) (set! cont (lambda () r))]
|
[(r) (lambda () r)]
|
||||||
[rs (set! cont (lambda () (apply values rs)))]))
|
[rs (lambda () (apply values rs))])))
|
||||||
(cont))))
|
(set! cont (case-lambda
|
||||||
(define (generator) (cont))
|
[() (ret)]
|
||||||
|
[_ (error 'generator "cannot send values to a ~a"
|
||||||
|
"generator that has terminated")]))
|
||||||
|
(ret)))]
|
||||||
|
[_ (error 'generator
|
||||||
|
"cannot send a value to a generator before it starts")]))
|
||||||
|
(define (generator . xs) (apply cont xs))
|
||||||
generator))
|
generator))
|
||||||
|
|
||||||
(define-syntax-rule (infinite-generator body0 body ...)
|
(define-syntax-rule (infinite-generator body0 body ...)
|
||||||
|
|
|
@ -235,15 +235,16 @@
|
||||||
(for/list ([x (in-generator (helper 0) (helper 1) (helper 2))])
|
(for/list ([x (in-generator (helper 0) (helper 1) (helper 2))])
|
||||||
x)))
|
x)))
|
||||||
|
|
||||||
|
(let ([g (lambda () (generator (yield 1) (yield 2) (yield 3)))])
|
||||||
|
(let ([g (g)]) (test '(1 2 3) list (g) (g) (g)))
|
||||||
|
(let ([g (g)]) (test '(1 2 3 10 10) list (g) (g) (g) (g 10) (g)))
|
||||||
|
(let ([g (generator (yield (yield (yield 1))))])
|
||||||
|
(test '(1 2 3 4 4 4) list (g) (g 2) (g 3) (g 4) (g) (g))))
|
||||||
|
|
||||||
(let* ([helper (lambda (pred num)
|
(let* ([helper (lambda (pred num)
|
||||||
(for ([i (in-range 0 3)])
|
(for ([i (in-range 0 3)]) (yield (pred (+ i num)))))]
|
||||||
(yield (pred (+ i num)))))]
|
[g1 (generator (helper odd? 1) (yield 'odd))]
|
||||||
[g1 (generator
|
[g2 (generator (helper even? 1) (yield 'even))])
|
||||||
(helper odd? 1)
|
|
||||||
(yield 'odd))]
|
|
||||||
[g2 (generator
|
|
||||||
(helper even? 1)
|
|
||||||
(yield 'even))])
|
|
||||||
(test '(#t #f #f #t #t #f odd even) 'yield-helper
|
(test '(#t #f #f #t #t #f odd even) 'yield-helper
|
||||||
(list (g1) (g2) (g1) (g2) (g1) (g2) (g1) (g2))))
|
(list (g1) (g2) (g1) (g2) (g1) (g2) (g1) (g2))))
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user