Scheme:call/ccパズル

Scheme:call/ccパズル

comp.lang.schemeのポストより:

次のコードが何をするか、コードを走らせることなく述べよ。

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

くれぐれも、自分で考える前にgoshに上の式を打ち込まないように!

正解はTaylor Campbellのポストにある。

以下は回答に触れるので、自力で解きたい人は注意。 なお、答えを確かめるにはgoshではなくguileを使うべし。 その理由は以下に述べる。


Shiroが最初に考えた回答は、 Taylor Campbellの最初のポスト(誤り) と同じだった。 つまり、最初にnewline, '*', newlineと来て、あとはずっと'*'が出力される、 というもの。

で、goshで実行してみると、確かにその通りになる。 だが、実はそれは正しくなかったのだ。

正解は一行にひとつづつ'*'が増えて行くというもので、 guileで実行すれば確かにそうなる。

というわけで、Shiroにとっての問題は、Gaucheのどこがおかしいのか? ということになったわけだ。

Gaucheでも、let*をlambdaに手で展開すると正しい出力が得られる。

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

しかし、Gaucheのコンパイラはlet系の構文はlambdaへとは展開せず、 専用のインストラクションへとコンパイルしている。 そのへんがまずいらしい。


※現在のバージョン(0.8.7)のgoshで実行すると正しい結果を得られる。2006/08/01 04:28:13 PDT

Tags: 継続, call/cc, Puzzle


Last modified : 2013/04/26 04:03:06 UTC