継続
Schemeには他の言語には存在しない継続という言語機能が存在する プログラムの「継続」を保存して、それを呼ぶとそこに飛ぶ機能
理解してしまえば何てことない機能なんだけど、イメージが掴みにくいせいか、理解に苦労することがある
抽象的な概念は理解しづらいもの、モナドしかり
説明する機会があるかもしれない(多分ない)のでまとめておこうと思う
呼ぶと現在のコールスタックを保存しているもので上書きするだけ
結果的にcall/ccを実行した位置に飛ぶことになる
何度でも呼べるだとか忘れて、一度だけ呼ぶケースだけ考えるなら、大域脱出そのものである
code:scheme
(call/cc
(lambda (break)
(for-each
(lambda (l)
(if (string=? l "END")
(break)
(begin
(display l)
(newline)))) longlist)))
(some-func foo bar)
と
code:python
for l in longlist:
if l == "END":
break
else
print(l)
someFunc(foo, bar)
は等価。両方とも、breakが評価された時点でsome-funcの直前へと飛ぶ
正確にはcall/ccの外側
他の言語と違うのは、このbreakに相当する部分を変数に突っ込んで保存できるという所だ
そのため第一級継続という言い方もされる
仕様上何度でも同じ場所に飛べるし、実装する側はコールスタックを全部保存している必要がある
ナイーブに実装するなら、コールスタック全部ヒープに抱えて解放はGCにやらせればいい
Gaucheは継続切り出した時点で全部ヒープに移してた気がする 自作の処理系はコールスタックがmutableだったから継続呼ばれた時点で全部にCopyOnWriteフラグ立てて、到達した段階でフラグ立ってたらコピーしてた あれこれ考えたけど、継続の理解の難しさよりプログラムの評価順序の理解の難しさな気がしてきた
人類は皆Schemeを実装してみればいいのでは
実装するには、継続がサポートされている言語(CとSchemeとRubyくらいしか見たことがない)を使うか、コールスタックを自作するしかない 別にVMじゃなくても書けそうだけどスケールしなさそう