goal:
(define (f)
(yield 0)
(yield 1)
(return 2))return は全体の返り値.そこで終わり.
yield はまだ続きのある、一旦の返り値.
(f)
; => 0
(f)
; => 1
(f)
; => 2
(f)
; => 2
(f)
; => 2と使えるようになる.
(define (f)
(let/cc return
(let/cc br
(set! f (lambda () (br)))
(return 0))
(let/cc br
(set! f (lambda () (br)))
(return 1))
(return 2)
))return は、(f)からの大域脱出で、
1つ目の br は、
(let/cc br
(set! g (lambda () (br)))
(return 1))
(return 2)を、2つ目の br は、
(return 2)を表す継続.
次のように動く
gosh> (f)
0
gosh> (f)
1
gosh> (f)
2
gosh> (f)
2
gosh> (f)
2
そのように書き換えるマクロ
(define-macro (coroutine f . bodies)
(define (rewrite-yield exp)
(cond ((and (pair? exp) (equal? (car exp) 'yield))
`(let/cc br (set! ,f (lambda () (br)))
(return ,@(cdr exp))))
((list? exp) (print exp) (map rewrite-yield exp))
(else exp)))
`(define (,f)
(let/cc return ,@(map rewrite-yield bodies))))
(coroutine f
(begin (yield -1) (yield 0))
(yield 1)
(return 2))gosh> (f)
-1
gosh> (f)
0
gosh> (f)
1
gosh> (f)
2
gosh> (f)
2
gosh> (f)
2
すごいよくある使い方
(coroutine g
(let loop ((i 0))
(yield i)
(loop (+ i 1)))
(return #f))gosh> (g)
0
gosh> (g)
1
gosh> (g)
2
gosh> (g)
3
gosh> (g)
4
gosh>