call/cc パズル (2)

バックアップソフトの起動イメージ作成中。昨晩中断したナニを再開してみる。
現時点ではちょっと戻って

((lambda (a)
   (PRINT-AND-NEXT-REPL
    (let* ((yin ((lambda (foo) (newline) foo) a))
	   (yang ((lambda (foo) (write-char #\*) foo)
		  (call/cc (lambda (bar) bar)))))
      (yin yang))))
 #<continuation yang>)

で出力されている情報としては

*I

# I はカーソルとして見ています (テキストもそうなっている模様
上記を eval するトコから再開。まず引数 a に # が束縛されて展開。

(let* ((yin ((lambda (foo) (newline) foo) #<continuation yang>))
       (yang ((lambda (foo) (write-char #\*) foo)
	      (call/cc (lambda (bar) bar)))))
  (yin yang))

これ見て分かるのは

  • 改行が出力される
  • 新たな継続ができる (多分 * も出力される

というあたりでしょうか。テキストでは # という書き方になっているのでこちでもそれ方式を踏襲。
で、yang に束縛される継続は以下かな、と言いつつ昨晩のエントリをカンニングしてたらなんか意味不明な式が書かれているのを発見。何だこれは。

;; #<continuation yang>
(lambda (a)
  (PRINT-AND-NEXT-REPL
   (let* ((yang a))
     ((lambda (a)
	(PRINT-AND-NEXT-REPL
	 (let* ((yin ((lambda (foo) (newline) foo) a))
		(yang ((lambda (foo) (write #\*) foo)
		       (call/cc (lambda (bar) bar)))))
	   (yin yang)))) yang))))

ええと、# を展開してるんだな。引数の名前がカブッてますが問題ないと見て修正はスルー。なるほど、と言いつつまずこうなるか

;; #<continuation yang'>
(lambda (a)
  (PRINT-AND-NEXT-EVAL
   (let* ((yang a))
     (#<contiuation yang> yang))))

で、# と置き換えて以下

;; #<continuation yang'>
(lambda (a)
  (PRINT-AND-NEXT-EVAL
   (let* ((yang a))
     (lambda (a)
       (PRINT-AND-NEXT-EVAL
	(let* ((yang a))
	  ((lambda (a)
	     (PRINT-AND-NEXT-REPL
	      (let* ((yin ((lambda (foo) (newline) foo) a))
		     (yang ((lambda (foo) (write #\*) foo)
			    (call/cc (lambda (bar) bar)))))
		(yin yang)))) yang)))) yang)))

で良いのだろうか。これが yang に束縛された状態で

(yin yang)

が評価される模様。ちなみに上記の評価が始まる時点で

*
*I

という形になっているか。しかし (yin yang) は正確には

(#<continuation yang> #<continuation yang'>)

になってるんだよな。これを両方いきなり置き換えるのは微妙なのでとりあえず先頭からヤッてみる。テキストもそうしてますね。

((lambda (a)
  (PRINT-AND-NEXT-REPL
   (let* ((yang a))
     ((lambda (a)
	(PRINT-AND-NEXT-REPL
	 (let* ((yin ((lambda (foo) (newline) foo) a))
		(yang ((lambda (foo) (write #\*) foo)
		       (call/cc (lambda (bar) bar)))))
	   (yin yang)))) yang))))
 #<continuation yang'>)

これを eval すると

(PRINT-AND-NEXT-REPL
 (let* ((yang #<continuation yang'>))
   ((lambda (a)
      (PRINT-AND-NEXT-REPL
       (let* ((yin ((lambda (foo) (newline) foo) a))
	      (yang ((lambda (foo) (write #\*) foo)
		     (call/cc (lambda (bar) bar)))))
	 (yin yang)))) yang)))

なんか変数名がカブリまくっててワケワカ。ヤリ方が悪いのか。

もう一度リトライ

って日本語変。ええと昨晩のエントリによると

(let* ((yin ((lambda (foo) (newline) foo)
             (call/cc (lambda (bar) bar))))
       (yang ((lambda (foo) (write-char #\*) foo)
              (call/cc (lambda (bar) bar)))))
  (yin yang))

なソレで yin が束縛されるオブジェクトは

(lambda (a) (PRINT-AND-NEXT-REPL ((lambda (foo) (newline) foo) a)))

となっている。この書き方もあまり良くないなぁ。何が根拠なのかが自分でも微妙。これは自分でヤろうとしちゃ駄目だな。テキストを追い掛けさせて頂きます。
でもやっぱ 上記のお題で yin と yang に具体的にどんなものが束縛されるか、はきちんと理解してないと微妙な気がする。
まず yin には

;; #<continuation yin>
(lambda (a)
  (PRINT-AND-NEXT-REPL
   (let* ((yin ((lambda (foo) (newline) foo) a))
	  (yang ((lambda (foo) (write-char #\*) foo)
		 (call/cc (lambda (bar) bar)))))
     (yin yang))))

をそのまま戻す手続き

((lambda (foo) (newline) foo) #<continuation yin>)

が束縛されている、で良いのかな。それとも

;; #<continuation yin>
(lambda (a)
  (PRINT-AND-NEXT-REPL
   (let* ((yin ((lambda (foo) (newline) foo) 
		((lambda (foo) (newline) foo) a)))
	  (yang ((lambda (foo) (write-char #\*) foo)
		 (call/cc (lambda (bar) bar)))))
     (yin yang))))

になるんかな。本文の記述的にはこちらなのでしょうか。ビンゴ前提で yang も同じコトしてみると

;; #<continuation yang>
(lambda (a)
  (PRINT-AND-NEXT-REPL
   (let* ((yang ((lambda (foo) (write #\*) foo) a)))
     ((lambda (a)
	(PRINT-AND-NEXT-REPL
	 (let* ((yin ((lambda (foo) (newline) foo) 
		      ((lambda (foo) (newline) foo) a)))
		(yang ((lambda (foo) (write #\*) foo)
		       (call/cc (lambda (bar) bar)))))
	   (yin yang)))) yang))))

というカンジ??

STEP 1

(yin yang) の評価。こうなって

(#<continuation yin> #<continuation yang>)

先頭のみ置き換える

((lambda (a)
   (PRINT-AND-NEXT-REPL
    (let* ((yin ((lambda (foo) (newline) foo) 
		 ((lambda (foo) (newline) foo) a)))
	   (yang ((lambda (foo) (write-char #\*) foo)
		  (call/cc (lambda (bar) bar)))))
      (yin yang))))
 #<continuation yang>)

eval してみる

(PRINT-AND-NEXT-REPL
 (let* ((yin ((lambda (foo) (newline) foo) 
	      ((lambda (foo) (newline) foo) #<continuation yang>)))
	(yang ((lambda (foo) (write-char #\*) foo)
	       (call/cc (lambda (bar) bar)))))
      (yin yang)))

あららら。これって改行が二発連続で入ってしまう形になってるんですが大丈夫か。

やっぱ

違うんだろうなぁ。とりあえずの理解として yin は

;; #<continuation yin>
(lambda (a)
  (PRINT-AND-NEXT-REPL
   (let* ((yin a)
          (yang (call/cc identity)))
     (yin yang))))

が束縛されててテキストによればこれが call されたら newline される、と。同様に yang は

;; #<continuation yang>
(lambda (a)
  (PRINT-AND-NEXT-REPL
   (let* ((yang a))
     ((lambda (a)
	(PRINT-AND-NEXT-REPL
	 (let* ((yin ((lambda (foo) (newline) foo) a))
		(yang ((lambda (foo) (write #\*) foo)
		       (call/cc (lambda (bar) bar)))))
	   (yin yang)))) yang))))

あるいは簡易に書くと

;; #<continuation yang>
(lambda (a)
  (PRINT-AND-NEXT-REPL
   (let* ((yang a))
     (#<continuation yin> yang))))

か。で、これも call されたら (write #\*) するのか。で、最初の (yin yang) な呼び出しの前にそれぞれ上記の継続がセットされる時に改行と * が出力されて準備完了、と。このあたりは三度目だか四度目だか分かりませんが、さくっとイメージできるようになってるのかなぁ。
で、次ですが (yin yang) はそれぞれ束縛されているものと置き換えられて以下

(#<continuation yin> #<continuation yang>)

# が call されるので改行される。で先頭のみ置き換えると以下

((lambda (a)
   (PRINT-AND-NEXT-REPL
    (let* ((yin a)
	   (yang (call/cc identity)))
      (yin yang))))
 #<continuation yang>)

で、eval すると

(PRINT-AND-NEXT-REPL
 (let* ((yin #<continuation yang>)
	(yang (call/cc identity)))
   (yin yang)))

ええと上記は yin に # が束縛される時点で * が出るとの事。あれ、違うな。改行されるって書いてあるぞ。
ここが微妙なんだ。そうか成程。以下な形で省略されていますが

;; STEP 0
(let* ((yin (call/cc identity))
       (yang (call/cc identity)))
  (yin yang))

束縛セットする時に yin セット時には改行されるし yang セット時には * が出るのか。いいのかなぁ。

続き

以下な形に展開されるとの記述ですが、この時点でスデに * は出ているはず、というのは間違いで改行は出ているけど、yang に call/cc の戻りを束縛する時点で * が出る、というのが多分正解

(PRINT-AND-NEXT-REPL
 (let* ((yang (call/cc identity)))
   (#<continuation yang> yang)))

あと上記で yang に束縛される継続は新たに作られるので # という書き方で別なモノという事を表現している。このあたりまでは来れてるんだよなぁ。(とほほほ
#

;; #<continuation yang'>
(lambda (a)
  (PRINT-AND-NEXT-EVAL
   (let* ((yang a))
     (lambda (a)
       (PRINT-AND-NEXT-EVAL
	(let* ((yang a))
	  ((lambda (a)
	     (PRINT-AND-NEXT-REPL
	      (let* ((yin ((lambda (foo) (newline) foo) a))
		     (yang ((lambda (foo) (write #\*) foo)
			    (call/cc (lambda (bar) bar)))))
		(yin yang)))) yang)))) yang)))

と上の方で書いている (おそらくこれは間違い)。簡易に書くと

;; #<continuation yang'>
(lambda (a)
  (PRINT-AND-NEXT-REPL
   (let* ((yang a))
     (#<continuation yang> yang))))

になるのか。簡易バージョンの # で置き換えてみると以下

;; #<continuation yang'>
(lambda (a)
  (PRINT-AND-NEXT-EVAL
   (let* ((yang a))
     ((lambda (a)
	(PRINT-AND-NEXT-REPL
	 (let* ((yang a))
	   (#<continuation yin> yang))))
      yang))))

あ、なんとなくどうなるか、がイメージできてきたっぽい。おそらくは

;; #<continuation yang''>
(lambda (a)
  (PRINT-AND-NEXT-REPL
   (let* ((yang a))
     (#<continuation yang'> yang))))

ってなるのではないかな。もうちょっと読み進めながら自分メモ。結局

(#<continuation yang> #<continuation yang'>)

で、先頭置き換えで

((lambda (a)
   (PRINT-AND-NEXT-REPL
    (let* ((yang a))
      ((lambda (a)
	 (PRINT-AND-NEXT-REPL
	  (let* ((yin ((lambda (foo) (newline) foo) a))
		 (yang ((lambda (foo) (write #\*) foo)
			(call/cc (lambda (bar) bar)))))
	    (yin yang)))) yang))))
 #<continuation yang'>)

になりますがこれを eval する直前での出力は

*
*

になっているはず。テキスト的にも OK です。ちょっとここでテキストにならってシンプルな書き方で

(#<continuation yang> #<continuation yang'>)

を書いてみよう。#

;; #<continuation yang>
(lambda (a)
  (PRINT-AND-NEXT-REPL
   (let* ((yang a))
     (#<continuation yin> yang))))

なので以下か

((lambda (a)
   (PRINT-AND-NEXT-REPL
    (let* ((yang a))
      (#<continuation yin> yang))))
 #<continuation yang'>)

一応テキストとは整合してます。で、上記を eval したら

(PRINT-AND-NEXT-REPL
 (let* ((yang #<continuation yang'>))
   (#<continuation yin> yang)))

になってここで yang に # が束縛される時に * が出力される。次に評価するのは

(#<continuation yin> #<continuation yang'>)

になります。

微妙

テキストには call される時、という書き方がされているんですが改行とか * 出力とかのトリガとしては基本的に yin とか yang への代入時限定、になっている。call って微妙だなぁ。とりあえず昼寝するのでエントリ投入。なかなか終わりません。

つづき

#

;; #<continuation yin>
(lambda (a)
  (PRINT-AND-NEXT-REPL
   (let* ((yin a)
          (yang (call/cc identity)))
     (yin yang))))

なので (# #) は

((lambda (a)
   (PRINT-AND-NEXT-REPL
    (let* ((yin a)
	   (yang (call/cc identity)))
      (yin yang))))
 #<continuation yang'>)

か。これは STEP 6' の状態ですよね。eval すると

(PRINT-AND-NEXT-REPL
 (let* ((yin #<continuation yang'>)
	(yang (call/cc identity)))
   (yin yang)))

ってなりますな。現状としては出力は

*
**

なので yin、yang に何かが束縛される時に改行と * が出力

*
**
*

になって

(#<continuation yang'> #<continuation yang''>)

がナニ。ちなみに新たに作られる継続は

;; #<continuation yang''>
(lambda (a)
  (PRINT-AND-NEXT-REPL
   (let* ((yang a))
     (#<continuation yang'> yang))))

で OK かな。デバッグプリントが出力されるタイミングを勘違いしていたのが敗因。