throw_cont_calculate_handlers() 手続き (2)
とか dynamic-wind とか。あるいは throw_cont_body() 手続きとか。
とりあえず handlers の扱いについてメモ。長いので引用してなかったみたいなんですが、R5RS によれば (dynamic-wind before thunk after) で以下に要約
- thunk の中で補足した継続が起動された時点で thunk の呼び出しの動的範囲に入る
- thunk 実行中にその範囲外で補足した継続が起動された時点で thunk の呼び出しの動的範囲を抜ける
- dynamic-wind がネストしていた時に 2 つめの thunk の中でその範囲外で補足した継続が起動された場合、2 つめ (内側) の after が呼び出されて、1 つめ (外側) の after が呼び出される (はず)
- ネストした dynamic-wind の 2 つめの thunk の中で補足した継続が起動された場合、1 つめ (外側) の before が呼び出された後に 2 つめ (内側) の before が呼び出される
- 継続の起動によって before と after の両方が呼び出される形になった場合には after の呼び出しが優先される
要約がビンゴかダウトかは不明ですが、R5RS の dynamic-wind の項に記述されている事項は throw_cont_calculate_handlers() 手続きの記述にぴったりハマります。
- before (ep->handlers) は reverse
- まず after (vm->handlers) からリストに append される
- SCM_APPEND1 は追加する cons を末端に置きます
- after は内側から順にリストに置かれる
- after の処理が終わった時点で before の処理
- 順番的には after -> before の順で呼び出される
要約が要約になってないので
実例でナニ。まず thunk の中で他所で補足された継続が起動されるケース。
(dynamic-wind (before) ((lambda () (cont))) (after))
cont は上記の通り、外部で補足された継続 (別の dynamic-wind の thunk の中で補足されたものではない事にします)。この時点では vm->handlers に ((before . after)) なリストが格納されてます。ep->handlers は基本空リスト。
という事で throw_cont_calculate_handlers() のソースによれば戻されるリストは ((after)) になるのでしょうか。この場合は after が呼び出された後は継続が起動される。
逆に外部で補足された継続が起動される場合は ep->handlers は基本空リストで vm->handlers に ((before . after)) なナニ。
ネストするケース
例えば
(dynamic-wind (before1) (thunk1) ;; cont に継続を格納 (after1))
の thunk1 で補足された継続を
(dynamic-wind (before2) ((lambda () (dynamic-wind (before3) ((lambda () (cont))) (after3)))) (after2))
みたいなカンジだった場合、R5RS によれば
- after3
- after2
- before1
して継続の実行開始なはず。このケースだと throw_cont_calculate_handlers() から戻るリストは
((after3 (before2 after2)) (after2) (before0))
になるのかなぁ。一応確認。
gosh> (define l '((after3 (before2 after2)) (after2) (before0))) l gosh> (caar l) after3 gosh> (cdar l) ((before2 after2)) gosh> (cdr l) ((after2) (before0)) gosh> (caar (cdr l)) after2 gosh> (cdar (cdr l)) () gosh> (caar (cdr (cdr l))) before0 gosh> (cdar (cdr (cdr l))) () gosh>
一応なんとかなってる模様。逆のケースとか before と after 混在なナニが確認したいんですが時間切れ。