コルーチンのお勉強
プログラミングGaucheのコルーチン(19.8)内容のお勉強。
P299に載っているexitのための手続きが定義されるほうのコルーチンを定義するためのマクロ定義の解読。
(use util.queue) (define *tasks* (make-queue) ) (define-syntax define-coroutine (syntax-rules () [ (_ (routine yield) body ...) (define (routine) (call/cc ( lambda(return) (define (yield) (call/cc (lambda (cont) (enqueue! *tasks* cont) (return)) ) ) body ...)) ((dequeue! *tasks*))) ] [ (_ (routine yield exit) body ...) (define (routine) (call/cc ( lambda (escape) (call/cc ( lambda(return) (define (yield) (call/cc (lambda (cont) (enqueue! *tasks* cont) (return)) )) (define (exit) (call/cc (lambda (cont) ( (enqueue! *tasks* cont) (escape) ) ) ) ) body ...)) ((dequeue! *tasks*) ) ) ) ) ]))
まず、exitのないほう。
コルーチン
これによって返される手続き(コルーチン)では、call/ccによりコルーチン呼び出し時の継続(return変数)の取得を行う。
このcall/cc内でbodyの実行を開始する(=他の継続が呼ばれないかぎり、このbodyの実行が続けられる)。call/ccを抜けて(<=他の継続が呼ばれて)このコルーチン呼び出し時の継続に戻ったときは、実行キューから継続を取り出し実行。
yield手続き
内側で定義される他のコルーチンを呼び出す手続き(yield)では、call/ccにより継続を取得して後で呼び出されるように実行キューに入れてから、
コルーチン呼び出し時の継続を呼び出す。この結果は実行キューからの取り出し+実行となる。
exitをつける場合
抜けるための継続取得
まず、再上位にcall/ccが呼び出される。これにより取得した継続がコルーチンの実行と実行キューの継続から抜けるためのものとなる。
exit手続き
exitの定義は、再開されたときに実行されるように現在の継続をキューに入れてから、コルーチンの最上位の継続を呼び出すことにより、コルーチンの実行と実行キューの継続から抜ける。