Cyanの継続
思考実験: returnを関数と思ってみる話 - d.y.d.
http://shinh.skr.jp/m/?date=20090307#p11
Cyanを知ってから継続を勉強したというド素人なんですが、
globalVar = 0 hello = ^(): globalVar = return return(0) x = hello() say x say globalVar(1+x) say x say "done."
0 1 done.
トップレベルからの継続(この言い回しが正しいのか分かってない)ではx=hello()のとこだけが得られて
main = ^(): globalVar = 0 break = return hello = ^(): globalVar = return return(0) x = hello() say x if (x == 5): break("done."); globalVar(x+1) say main()
だと
0 1 2 3 4 5 done.
mainが終わるまでの処理も含まれるってのは、REPLとかでこの方が都合が良いからかなーと思ったんだけどどうなんだろう。
って、マニュアルに「トップレベルまでの残りの計算をする関数」と書いてあった。何も特別扱いってことではないのか。
Gaucheでも試してみたら同じ結果に。
(define cont 0) ;(define (main) (define (hello) (call/cc (lambda (c) (set! cont c) 0))) (define x (hello)) (print x) (print (cont (+ x 1))) (print x) (print "done.");) ;(main)
0 1 done. #t
コメント外すと無限ループ。
検索したらつい先日同じ話が継続の違い - Higepon’s blogにあった。見落としてた…
R6RSはまた話がややこしいらしい。
あと
retret = ^(): return(return) x = retret() print x()()()()()()()()()
これで何が起こるかすぐ理解できなかったので整理してみる。
2行目でretretが呼び出された時点での継続は ^(a): x = a みたいな感じ。
return(return)では x = return が評価されて、retretからは戻らず3行目に飛ぶ。
3行目はx()の時点で先のreturnに処理が飛ぶのでprintとか後ろの()()()...は無視。
で、x(1)だったら x = 1 となるけど、引き数を渡さなかった場合どうなるのかというと
cyan> x = callcc^(c): cont = c; 0 => 0 cyan> cont(10) => 10 cyan> x => 10 cyan> cont() => [] cyan> x => []
エラーになりそうな気もするけど[[]]が入るらしい。というわけで最終行ではx = [[]]が実行されてプログラム終了、ってことで良いのかな。
ちなみに引数ナシの継続呼び出しは、gaucheでもエラーにならず#undefとなった。
gosh> (define cont 0) cont gosh> (define x (call/cc (lambda (c) (set! cont c) 1))) x gosh> (cont 10) x gosh> x 10 gosh> (cont) x gosh> x #<undef>
これも過去にどっかで議論されてそう。
限定継続
まったく知らないので僕でもわかる継続と部分継続 - まめめも 見て勉強。
うは、shift, resetの作り方全くわからん。
http://community.schemewiki.org/?composable-continuations-tutorialを見るとcall/ccで定義できちゃうってことなのかな。関係ないけどマウスオーバーすると楽しいなこれ。
おまけ
returnXXXみたいなのはマクロで簡単に出来そう、と思ったらSymbol.internがなかったので無理なのでした。 String.internがあった!(->追記)
return[name]みたいな書き方は、スコープを考慮した実現方法が思い付かない。
追記
コメントより
internはStringにあります
うは、見落としてた、というかSymbol.internじゃおかしいよな確かに。ダメだなー。
mac(mydef)^(name, func): _ret := ("return_" + name.to_s()).intern() _body := Block.new([`(?_ret := return), *func.body.list]) _func := Function.new(func.params, _body) `def(?name, ?_func) mydef(findFirstNegative)^(arr): arr.foreach^(elem): if (elem < 0): return_findFirstNegative(elem) error("not found") say findFirstNegative([123, 45, -67, 8, -9])
実行
-67
できたできた