call/cc リハビリ (3)
昨晩、call/cc に入った所で腑に落ちない部分にぶち当たり、力尽きてました。
ええと
_続きの計算はいたるところにある。_という件。
(* 2 (fact 10))
の (fact 10) の続きの計算は (lambda (a) (* 2 a)) だ、という事から以下。
;; (* 2 (fact 10)) (call-with-continuation-procedure (lambda (a) (* 2 a)) (lambda (cont) (cont (fact 10))))
call/continuation-procedure が定義されてればきちんと計算できる。
gosh> (define (call/continuation-procedure cont proc) (proc cont)) call/continuation-procedure gosh> (call/continuation-procedure (lambda (a) (* 2 a)) (lambda (cont) (cont (identity 2)))) 4 gosh>
ここから call/cc に繋げるあたりがナニ。こんなコードが書いてある。
(* 2 (call-with-continuation-procedure (lambda (* 2 a)) (lambda (cont) (cont (fact 10)))))
上記はさらに * 2 されます。ここが微妙だったんですが、上記のコードは * 2 してあるから、継続は (lambda (a) (* 2 a)) が渡されます、という概念を説明するためのものなんですね。
で、上記みたいなナニが call/cc 使えばこう書ける、と。
(* 2 (call/cc (lambda (cont) (cont (fact 10)))))
引数 cont には (lambda (a) (* 2 a)) が格納されるはず。試してみます。ええと、(lambda (a) (* 2 a)) な継続を捕捉するにはどうすりゃ良いか。
gosh> (define f #f) f gosh> (set! f (* 2 (call/cc (lambda (cont) cont)))) *** ERROR: operation * is not defined between 2 and #<subr continuation> Stack Trace: _______________________________________ gosh>
げ。叱られた。
gosh> (* 2 (call/cc (lambda (cont) cont)) ) *** ERROR: operation * is not defined between 2 and #<subr continuation> Stack Trace: _______________________________________ gosh>
何してるのか。こうか。
gosh> (set! f (* 2 (call/cc (lambda (cont) (cont (identity 2)) cont)))) 4 gosh> f 4 gosh>
これは f に計算結果が束縛されてるはず。こうするのか。
gosh> (* 2 (call/cc (lambda (cont) (set! f cont) (cont (identity 2))))) 4 gosh> f #<subr continuation> gosh> (f 3) 6 gosh>
なかなかに面倒ですね。
で
ここで PRINT-AND-NEXT-REPL が出てくるんですが、その前に上記で微妙だった * 2 なソレがナニ。具体的には_継続渡し形式への書き換えを試みてみる_というあたり。
;; call/ccの継続渡し形式への書き換えを試みてみる (* 2 ((lambda (cont) (cont (fact 10))) (lambda (a) (* 2 a))))
ここでの疑問点は二つ。
- * 2 以降の計算って?
- * 2 が放置
という事で REPL が出てきます。あー成程。このあたりの記述って、call/cc が何をしているのか、という事を分かってもらおうとしているのか。便宜的に継続渡しなソレを使って説明しているだけなんですね。
んで、* 2 以降の計算は REPL ですよ、という事で以下な式が出てくる。
(* 2 ((lambda (cont) (cont (fact 10))) (lambda (a) (PRINT-AND-NEXT-REPL (* 2 a)))))
置き換えて以下。
(* 2 ((lambda (a) (PRINT-AND-NEXT-REPL (* 2 a))) (fact 10)))
さらに置き換えて以下。
(* 2 (PRINT-AND-NEXT-REPL (* 2 (fact 10))))
例えば以下な例で
gosh> (* 2 (call/cc (lambda (cont) (cont (identity 2))))) 4 gosh>
先頭にある_* 2_は何処に行ったんだ、という疑問を払拭するために便宜的に PRINT-AND-NEXT-REPL が出てくる、と。上記のナニだと以下なカンジ?
(* 2 (PRINT-AND-NEXT-REPL (* 2 (identity 2))))
_* 2_の継続は REPL なので、という事で call/cc 自体はそこまで怪しい動作をしている訳ではないのだよ、という所にオチる模様。
ちょっと
休憩。
まだテキストの半分もいってないな。gdgd 読みつつゆっくりする予定。