switch generator' implementation to use prompt' and `call/cc'

Instead of `shift' and `reset'. Performance is a little better,
since `call/cc' acts as hint to the run-time system that the
continuation doesn't need to compose.
This commit is contained in:
Matthew Flatt 2012-09-18 13:51:45 -06:00
parent 21e0d9e031
commit 07e5526d6a

View File

@ -52,7 +52,7 @@
[(v) ((current-yielder) v)] [(v) ((current-yielder) v)]
[vs (apply (current-yielder) vs)])) [vs (apply (current-yielder) vs)]))
(define yield-tag (make-continuation-prompt-tag)) (define yield-tag (make-continuation-prompt-tag 'yield))
(define-syntax (generator stx) (define-syntax (generator stx)
(syntax-case stx () (syntax-case stx ()
@ -84,20 +84,28 @@
(define (create-generator start) (define (create-generator start)
(let ([state 'fresh]) (let ([state 'fresh])
(define (yielder . vs)
(set! state 'suspended)
(call/cc (lambda (k)
(set! cont k)
(apply abort-current-continuation yield-tag vs))
yield-tag))
(define (cont . init-formals) (define (cont . init-formals)
(define (yielder . vs)
(set! state 'suspended)
(shift-at yield-tag k (set! cont k) (apply values vs)))
(set! state 'running) (set! state 'running)
(reset-at yield-tag (call-with-values
(parameterize ([current-yielder yielder]) (lambda ()
(call-with-values (apply start init-formals))
(lambda () ;; get here only on at the end of the generator
(apply start init-formals)) (lambda rs
;; get here only on at the end of the generator (set! cont (lambda () (set! state 'done) (apply values rs)))
(lambda rs (cont))))
(set! cont (lambda () (set! state 'done) (apply values rs))) (define (call-cont vs)
(cont)))))) (call-with-continuation-prompt
(lambda ()
(parameterize ([current-yielder yielder])
(apply cont vs)))
yield-tag
values))
(define (err [what "send a value to"]) (define (err [what "send a value to"])
(raise-arguments-error 'generator (raise-arguments-error 'generator
(format "cannot ~a a ~a generator" what state) (format "cannot ~a a ~a generator" what state)
@ -106,15 +114,15 @@
(case-lambda (case-lambda
[() (if (eq? state 'running) [() (if (eq? state 'running)
(err "call") (err "call")
(begin (set! state 'running) (cont)))] (begin (set! state 'running) (call-cont null)))]
;; yield-tag means return the state (see `generator-state' below) ;; yield-tag means return the state (see `generator-state' below)
[(x) (cond [(eq? x yield-tag) state] [(x) (cond [(eq? x yield-tag) state]
[(memq state '(suspended running fresh)) [(memq state '(suspended running fresh))
(set! state 'running) (set! state 'running)
(cont x)] (call-cont (list x))]
[else (err)])] [else (err)])]
[xs (if (memq state '(suspended running fresh)) [xs (if (memq state '(suspended running fresh))
(begin (set! state 'running) (apply cont xs)) (begin (set! state 'running) (call-cont xs))
(err))])) (err))]))
(define self (make-generator generator)) (define self (make-generator generator))
self)) self))