應用序 or 正則序?

dennis_zane發表於2007-05-08
    這是《計算機程式的構造與解釋》中的一道習題,如何去判斷一個scheme直譯器是採用什麼方式進行求值的?應用序 or 正則序。應用序是先對引數求值而後應用,而正則序則相反——完全展開而後歸約求值。正則序相比於應用序,會部分存在重複求值的情況。習題是這樣的:
    Ben Bitdiddle發明了一種檢測方法,能夠確定直譯器究竟採用的哪種序求值,是採用正則序,還是採用應用序,他定義了下面兩個過程:
  
(define (p) (p))
(define (test x y)
    (
if (= x 0)
         
0
         y))
    而後他求值下列的表示式:
  
(test 0 (p))
如果直譯器採用的是應用序求值,ben將會看到什麼情況?如果是正則序呢?

    分別分析下這兩種情況下直譯器的求值過程:
1.如果直譯器是應用序,將先對過程test的引數求值,0仍然是0,(p)返回的仍然是(p),並且將無窮遞迴下去直到棧溢位,顯然,在這種情況下,直譯器將進入假死狀態沒有輸出。

2.如果直譯器是正則序,完全展開test過程:
(define (test 0 (p))
    (
if (= 0 0)
        
0
        (p))
接下來再進行求值,顯然0=0,結果將返回0。

    一般lisp的直譯器都是採用應用序進行求值。這個問題在習題1.6中再次出現。我們知道scheme已經有一個cond else的特殊形式,為什麼還需要一個if else的特殊形式呢?那麼我們改寫一個new-if看看:
(define (new-if predicate then-clause else-clause)
        (cond (predicate then
-clause)
              (
else else-clause)))

寫幾個過程測試一下:
(new-if (< 1 01 0)
結果一切正常,但是,當這3個引數是過程的時候會發生什麼情況呢?在這3個引數如果存在遞迴呼叫等情況下,直譯器也將陷入無限迴圈導致棧溢位!比如書中的求平方根過程用new-if改寫:
(define (new-if predicate then-clause else-clause)
        (cond (predicate then
-clause)
              (
else else-clause)))
(define (average x y)(
/ (+ x y) 2))
(define (square x) (
* x x))
(define (improve guess x)(average guess (
/ x guess)))
(define (good_enough
? guess x)
        (
< (abs (- (square guess) x)) 0.000001))
(define (sqrt_iter guess x)
        (new
-if (good_enough? guess x)
            guess
            (sqrt_iter (improve guess x) x)))   
(define (simple_sqrt x)(sqrt_iter 
1 x))

因為直譯器是應用序求值,將對new-if過程的3個引數求值,其中第三個引數也是一個過程(sqrt_iter (improve guess x) x)) 遞迴呼叫自身,導致無限迴圈直到棧溢位。



115949.html

dennis 2007-05-08 15:11 發表評論

相關文章