call/cc パズル

call/cc パズルですが、ハマッております。移動中にデスクトップに保管したコンテンツを読んだのですが途中で力尽きました。帰宅後に最初からリトライしてみます。
お題が以下

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

敗因は

  • call/cc が戻すのが何かがこんがらかってしまった
  • yin と yang に束縛されているものが何かワケワカ
  • 多分他にもありますが思い出せん

なんですが、とりあえずリトライ。

とりあえず

最初に yin に束縛されるオブジェクトは何か、というのがポイントか。上記の式を見るに

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

になるの? このあたりについても丁寧に解説あり。なるほど。

(EXTERNAL-EXPR ((lambda (foo) (newline) foo) (call/cc (lambda (bar) bar))))

という式が評価されるケイスでは call/cc が戻す継続は

(lambda (a)
  (EXTERNAL-EXPR ((lambda (foo) (newline) foo) a)))

という形になる、という事? だとすると 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))))

というコトになるのでしょうか。あるいは 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))))

かなぁ。
で、(yin yang) が評価される前に yin と yang に上記が束縛される時に順に改行が出力されて * が出力される。で、

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

が評価されてどうなるか、というと (テキストの通り # のみ

((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>)

これを適用したら確かに次は改行されるな。ちょっとこのあたりのイメージがまだ微妙。以下になるはず

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

なんか机上ベースのアレが続いてて、SICP 完全スルーな今日この頃だな。テキストにもありますが、ダッシュが付いた新たな # が yang に束縛予定。とりあえず紆余曲折も含め、遅くなってしまったので寝る。