2010年1月4日月曜日

問題1.6

Alyssa P. Hacker は if が特殊形式である理由が分からない。「condを利用し、普通の手続きとして定義してはいけないの?」と聞いた。Alyssa の友人の Eva Lu Ator はそうすることはもちろん出来るといって、if の新版を定義した:

(define (new-if predicate then-clause else-clause)
(cond (predicate then-clause)
(else else-clause)))

Eva は Alyssa にプログラムを見せた:

> (new-if (= 2 3) 0 5)
5
> (new-if (= 1 1) 0 5)
0
>

Alyssa は喜び、平方根のプログラムを書き直すのにnew-ifを使った:

(define (sqrt-iter guess x)
(new-if (good-enough? guess x)
guess
(sqrt-iter (improve-guess x)
x)))

Alyssa が平方根を計算するのにこれを使おうとすると、何が起きるか、説明せよ。

無限ループに陥ります。
問題はnew-ifが手続きであるから、です。ボディ部の評価に入る前に与えられた引数が全部評価されないとなりません。
Eva の例の場合は、再帰定義ではないので問題が生じないのですが、Alyssa が用いようとした手続きは再帰構造を持っています。従って、再帰部分であるnew-ifの第3引数を評価するとまたもや引数の展開が生じて、終了地点が無いまま無限ループに入ってしまうのです。
new-ifも本来はマクロを使って定義するべき、でしょう。これはSchemeの衛生的マクロで簡単に書くことが可能です。

(define-syntax new-if
(syntax-rules ()
((_ predicate then-clause else-clause)
(cond (predicate then-clause)
(else else-clause)))))

0 件のコメント:

コメントを投稿