自分の考えた、WiLiKi:Scheme:call/ccパズルの解説。
- 上のページから、模範解答へ飛べるので、そっちを見た方がよく分かる気もしますが、英語なので…‥。
- 折角なので、「何故Gauche?ではこうならないのか」も考えてみました。
(以下はネタバレなので、自力でパズルを解きたい人は読まない方がいいです)
(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の定義時に改行が、yangの定義時に*が出力される。
- この時点でのyinの中味をyin0、yangの中味をyang0と呼ぶ事にする。
- そして、一回目の(yin yang)、つまり(yin0 yang0)が評価され、最初のyinの定義中の、改行を出力する直前に戻る。
- そして、改行が出力され、yinが定義されるが、継続の引数としてyang0が指定されているので、二回目のyinには、yang0が入る事になる。
- この二回目のyinの中味を、yin1と呼ぶ事にする。つまり、yin1=yang0。
- そして、引き続き、二回目のyangが定義され、*が出力される。
- 同様に、二回目のyangをyang1と呼ぶ事にする。
- そして、二回目の(yin yang)、つまり(yin1 yang1)、更に言うならば(yang0 yang1)が評価され、yang0に戻る。
- *が出力され、新しいyangとして、yang1が定義される。
- そして、三回目の(yin yang)、つまり(yin0 yang1)が評価される事になる。
- ちなみに、ココがこのパズルの引っ掛け部分。
- 一見、(yin1 yang1)のように思えるが、ココはyang0の継続直後の(yin yang)なので、yinにはyin0が定義されている(guileの場合)。
- ココでyinがyin0ではなく、yin1だと思ってしまうと、*がずっと出力される結果となる。
- 改行が出力され、yinにはyang1が定義され、*が出力され、yangが定義される。
- この新しいyangを、yang2と呼ぶ事にする(継続の巻き戻しの為、「○回目のyang」等とハッキリ言えなくなっている…‥)
- そして、また(yin yang)、つまり、(yang1 yang2)が評価される。
- *が出力され、新しいyangとして、yang2が定義される(この時点でのyinはyin1)。
- そして、また(yin yang)が評価されるが、この時点でのyinはyang1が生成された時点でのyin、つまり、yin1=yang0。つまり、(yang0 yang2)が評価される。
- *が出力され、新しいyangとして、yang2が定義される(この時点でのyinはyin0)。
- そして、また(yin yang)が評価されるが、この時点でのyinはyang0が生成された時点でのyin、つまり、yin0。つまり、(yin0 yang2)が評価される。
- 改行が出力され、yinにはyang2が定義され、*が出力され、yangが定義される。
- あとは、この繰り返しで、延々とyang3, yang4, yang5...と生成され続けていく。
で、Gauche?ではどうしてそうならないのか、を考えると、
- 上記のパズルの引っ掛け部分に引っかかってしまっている
のが、一番に思いつく。
結論から書くと、
- 要するに、letが、「先にyinやyangのアドレスを用意してから、実体を計算する」のではなく、「実体を計算してから、yinやyangのアドレスを確保する」手順で実行されるなら、guile?と同じ解になる
のだと思う。
例えば、yang0の継続を辿って戻ってきた際に、この時点ではyinにはyin0が入っていれば、guile?と同じ挙動をすると思うが、上記の結果より、Gauche?では、この時点ではyinにはyin1(=yang0)が入っているようだ。
要するに、defineで変数だけ先に用意しておいて、ソレをset!しているのと同等の状態になっているのではと思う。
(ココで、実際に試しに修正して、結果が変わるのを確認して、パッチを送れれば、カッコ良いのだが…‥)
更に考えた結果→nekoie-call/ccパズル解:Gauche/src/compile.cを追ってみるテスト
ところで、この「call/ccを使って、letの変数定義部分の中に戻った際の挙動」って、R5RS?とかで規定されてたっけ?規定されていないなら、どっちが正解とかは言えない気も…‥。
最終更新 : 2004/04/10 20:04:14 JST