Shiroさんに教えてもらったyin-yang puzzleの回答。
課題のプログラムは次の通りです。
(let* ([yin ((lambda (foo) (newline) foo) (call/cc (lambda (bar) bar)))] [yang ((lambda (foo) (write-char #\*) foo) (call/cc (lambda (bar) bar)))]) (yin yang))
以下ネタバレ。
let*をlambdaと関数適用に分解して、名前をわかりやすくすると次のようになります。
((lambda (yin) ((lambda (yang) (yin yang)) ((lambda (yang*) (write-char #\*) yang*) (call/cc (lambda (cc) cc)) ; (B) ))) ((lambda (yin*) (newline) yin*) (call/cc (lambda (cc) cc)) ; (A) ))
注目するべき点は、Bで捕捉される継続では、yinになんらかの値が束縛されている、ということです。実際には、AかBで捕捉される継続のいずれかが束縛されます。Bの継続が束縛されている場合、その継続ではyinになんらかの値、具体的にはAかBで捕捉される継続のいずれかが束縛されており、Bの継続が束縛されている場合、その継続では……。
Aの継続が呼び出されると、改行して、引数で渡された値がyinに束縛されます。
Bの継続が呼び出されると、その継続が捕捉された時点でのyinへの束縛が再現され、アスタリスクが出力され、引数で渡された値がyangに束縛されます。
ステップを追うと次のとおり。
1. (newline), そしてAの継続がyinに渡される。ここで名前環境を{yin=A}と書く。
2. (write-char #\*), そしてBの継続がyangに渡される。このBの継続において、上述したとおり、yinにはAの継続が束縛されている。これを{yin=A, yang=B{yin=A}}と書く。
3. (yin yang)を呼ぶということは、(A B{yin=A})を呼ぶということ。Aに戻って(newline), そしてyin*, yinにはB{yin=A}が渡される。{yin=B{yin=A}}
4. (write-char #\*), そしてyangにはBの継続が渡されるが、このBの継続において、yinにはB{yin=A}が束縛されている。つまり{yin=B{yin=A}, yang=B{yin=B{yin=A}}}。
5. (yin yang)は(B{yin=A} B{yin=B{yin=A}})。Bに戻るが、そのときyinにはAが束縛された状態。(write-char #\*)を呼んで、yangには(yin yang)の引数であるB{yin=B{yin=A}}が渡される。{yin=A, yang=B{yin=B{yin=A}}}。
6. (yin yang)は(A B{yin=B{yin=A}})。Aに戻って(newline), そしてyinにはB{yin=B{yin=A}}が渡される。{yin=B{yin=B{yin=A}}}。
7. (write-char #\*), そしてyangにはBの継続が渡されるが、このBの継続において、yinにはB{yin=B{yin=A}}が束縛されている。{yin=B{yin=B{yin=A}}, yang=B{yin=B{yin=B{yin=A}}}}。
8. (write-char #\*), {yin=B{yin=A}, yang=B{yin=B{yin=B{yin=A}}}}
9. (write-char #\*), {yin=A, yang=B{yin=B{yin=B{yin=A}}}}
10. (newline), {yin=B{yin=B{yin=B{yin=A}}}}
11. (write-char #\*), {yin=B{yin=B{yin=B{yin=A}}}, yang=B{yin=B{yin=B{yin=B{yin=A}}}}}
12. (write-char #\*), {yin=B{yin=B{yin=A}}, yang=B{yin=B{yin=B{yin=B{yin=A}}}}}
13. ...
Rubyで書き直すと次の通り。
require 'continuation' def let(v, &block) block[v] end let(lambda {|foo| puts ''; foo }[callcc{|bar| bar }]) {|yin| let(lambda {|foo| print '*'; foo }[callcc{|bar| bar }]) {|yang| yin[yang] } }