I\'m trying to port yield
and yield from
from Python to Scheme.
Here is an implementation I\'ve done:
(define (coroutine ro
Something like this:
(define (make-generator procedure)
(define last-return values)
(define last-value #f)
(define (last-continuation _)
(let ((result (procedure yield)))
(last-return result)))
(define (yield value)
(call/cc (lambda (continuation)
(set! last-continuation continuation)
(set! last-value value)
(last-return value))))
(lambda args
(call/cc (lambda (return)
(set! last-return return)
(if (null? args)
(last-continuation last-value)
(apply last-continuation args))))))
Used like this:
(define test
(make-generator
(lambda (collect)
(collect 1)
(collect 5)
(collect 10)
#f)))
(test) ; ==> 1
(test) ; ==> 5
(test) ; ==> 10
(test) ; ==> #f (procedure finished)
Now we can wrap the internals into a macro:
(define-syntax (define-coroutine stx)
(syntax-case stx ()
((_ (name . args) . body )
#`(define (name . args)
(make-generator
(lambda (#,(datum->syntax stx 'yield))
. body))))))
Notice that define-coroutine
is implemented using syntax-case since we need to make yield
unhygienic.
(define-coroutine (countdown-from n)
(let loop ((n n))
(if (= n 0)
0
(loop (- (yield n) 1)))))
(define countdown-from-10 (countdown-from 10))
(define (ignore procedure)
(lambda ignore
(procedure)))
(map (ignore countdown-from-10) '(1 1 1 1 1 1)) ; ==> (10 9 8 7 6 5)
;; reset
(countdown-from-10 10) ; ==> 9
(countdown-from-10) ; ==> 8
;; reset again
(countdown-from-10 100) ; ==> 99