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>