2010年1月3日日曜日

問題1.5

Ben Bitdiddleは、彼の対面している解釈系が、作用的順序の評価を使っているか、正規順序の評価を使っているか決定するテストを発明した。次の二つの手続きを定義した:

(define (p) (p))

(define (test x y)
(if (= x 0)
0
y))

彼は次に式

(test1 0 (p))

を評価してみた。作用的順序の評価を使う解釈系で、Benはどういう振舞いを見るか。正規順序を使う解釈系で、彼どういう振舞いを見るか。説明せよ。(特殊形式ifの評価規則は、解釈系が正規順序と作用的順序のどちらを使うかに無関係に同じとする: 述語式を最初に評価し、その結果が帰結式と代替式のいずれを評価するかを決める。)

作用的順序の評価を使うインタプリタだと、(test1 0 (p))は無限ループに陥ります。
何故なら、testのボディが評価される前に引数が評価され、(p)が評価されて(p)となり、また(p)が評価され・・・と、引数の展開がどこまでも終わりません。結果、引数yの実引数の無限評価が引き起こり、永久にボディ部に入らないのです。
一方、正規順序を使うインタプリタだと、「必要になるまで」引数が評価されないので、(test1 0 (p))は0を返して終了します。何故なら正規評価では(p)が評価される事自体が無いから、です。
例示のコードの「正規順序」のエミュレートだと、マクロで記述して動作を見てみた方が良いでしょう。マクロはコードの展開前に引数を評価する事がありません。
とは言っても、Schemeの衛生的マクロだと記述出来そうにないんで、仕様範囲外の伝統的マクロ(レガシーマクロやコードタイプのマクロ等としばしば呼ばれる)で記述してみた方が良いでしょう。
PLT Schemeの場合は、次のようにして書いてみれば良いでしょう。

(require mzlib/defmacro) ;実装依存のdefine-macro使用を宣言

(define-macro (test-macro x y)
(if (zero? x)
0
y))

実行結果は以下の通りです。

> (test-macro 0 (p))
0
>

ちなみに旧いLispなんかの場合は、マクロを使うまでも無く、処理系のNEXPR型やFEXPR型の関数で簡単に確かめる事が出来たかもしれません。
そう言う意味では、問題の質としては旧いのかもな、とも思います。

0 件のコメント:

コメントを投稿