継続、call/cc

@mr_konn さん、 @cocoa_ruto さん、 @cocoa_ruto さんらによるcallccの挙動について
0
スマートコン @mr_konn

call/ccの挙動は知っているがちゃんと理解していないのでこの期に頑張ろう

2016-03-14 20:07:22
スマートコン @mr_konn

うーん、cc が入って簡約が比較的簡単な例をつくろう

2016-03-14 21:27:04
スマートコン @mr_konn

継続って評価戦略に依存しますよね?

2016-03-14 21:39:17
スマートコン @mr_konn

結局 call/cc っていうのは reset 即 shift みたいな理解で良いんだな

2016-03-14 22:26:24
スマートコン @mr_konn

call/cc は全体を reset で囲んである場合の shift だと勝手に誤解していた

2016-03-14 22:27:40
Yusuke Endoh @mametter

@mr_konn あれ、違うんでしたっけ。

2016-03-14 22:38:06
スマートコン @mr_konn

@mametter たとえば reset (3 + shift (const 12)) の答は 12 ですけど、3 + callcc (const 12) の答は15ですよね

2016-03-14 22:41:48
Yusuke Endoh @mametter

@mr_konn そうか。継続を呼ばないとそうなりますね。でも reset (shift (fun k -> (k 1) + 2)) は 3 だけど callcc (fun k -> (k 1) + 2) は 1 になるので単純に reset 即 shift でもない気がする

2016-03-14 22:47:47
スマートコン @mr_konn

@mametter あーそうか、確かにそうですね……。うーん、どう考えるのがいいんですかね……。

2016-03-14 22:49:27
Yusuke Endoh @mametter

@mr_konn callcc M は全体を reset で囲った上で shift (fun k -> k M) と同じ?(ただしプログラムは最後に exit するので reset には到達し得ないこととする)

2016-03-14 22:54:55
スマートコン @mr_konn

@mametter そうすると Mの中で k を使う時に型があわない気がします……

2016-03-14 22:58:05
Yusuke Endoh @mametter

@mr_konn 型とかいう発想を忘れていた。普通の継続の型は t -> \bot です。部分継続でも同じだと思いますが、プログラム全体を reset で囲むのは仮想的にはできるけど実際にはできなくて現実の型システムは通らないかも?という話かしら?

2016-03-14 23:08:38
スマートコン @mr_konn

@mametter たとえば callcc で囲われた部分全体が型 t だとした時の継続が t → ⊥ だということですよね。それはいいんですけど、この時 callcc M の M は (t → ⊥) 型を引数にとるので、k M って道理に合わないのでは……?と思ったのです

2016-03-14 23:12:34
Yusuke Endoh @mametter

@mr_konn 普通に間違えてますね。callcc M は shift (fun k -> k (M k)) と同じか

2016-03-14 23:15:26
スマートコン @mr_konn

@mametter ああそれですね!こうやってみてみると、call/cc はやっぱり不必要に複雑だという感じがしますね……。

2016-03-14 23:19:11
ると @cocoa_ruto

@mametter @mr_konn call/cc (λk. (k 1) + 1) + 2は3ですが、reset (shift (λk. k ((k 1) + 1)) + 2)は6ですし、reset (shift (λk. k ((k 1) + 1))) + 2は4です。

2016-03-14 23:27:09
Yusuke Endoh @mametter

@cocoa_ruto @mr_konn callcc (λk. (k 1) + 1) + 1 は reset (exit (shift (λk. k ((k 1) + 1)) + 2)) と同じという主張です。exit は引数を評価してプロセス終了するような何か

2016-03-14 23:30:57
スマートコン @mr_konn

@mametter @cocoa_ruto 手で展開していくと、exit が正格評価と定められているのでちゃんと 3 を返して終わる筈ですね。

2016-03-14 23:41:40
ると @cocoa_ruto

@mametter @mr_konn exitを許すならばそうなります。ただしネストした場合はexitではなく、「1つ外側の部分継続」になります。 gist.github.com/taku0/b3dd6298… で、その「1つ外側の部分継続」をどうやって取るのかという問題に行き着きます。

2016-03-15 00:00:06
スマートコン @mr_konn

@cocoa_ruto @mametter あーネストした場合については全然考えてなかったですね……。そもそも shift/reset で call/cc を表現しようというのが間違いという事なんですかね?

2016-03-15 00:04:02
ると @cocoa_ruto

@mr_konn @mametter 「1つ外側の部分継続」を動的スコープ変数に入れるとすれば、「call/ccとは、exit+shift/reset+動的スコープ変数」と言えます。

2016-03-15 00:09:14
スマートコン @mr_konn

@cocoa_ruto なるほど……。そうするとあんまり綺麗じゃなくなってかなしいですね……。

2016-03-15 00:10:32
ると @cocoa_ruto

@mr_konn @mametter 別の捉え方としては、部分継続が外側からk1, k2, k3であるときに、それにexitを付けて合成したexit.k1.k2.k3が普通の継続であるとも言えます(「部分」を全て繋げると「全体」になる)。

2016-03-15 00:10:39
Yusuke Endoh @mametter

@mr_konn @cocoa_ruto @mametter プログラム内で shift/reset 使わないでください ^^ 使いたいなら、shift/reset でエンコードした callcc を使って shift/reset を定義してください

2016-03-15 00:10:49
スマートコン @mr_konn

@mametter @cocoa_ruto あれ、今の話はcall/cc を二重以上にネストするという事ですよね……?

2016-03-15 00:15:00