天天看點

sicp 4.2.2小節部分習題

4.27,

;;; l-eval input:

(define count 0)

;;; l-eval value:

ok

(define (id x)

  (set! count (+ 1 count))

  x)

(define w (id (id 10)))

count

1

w

10

2

至于原因,w在沒有強迫求值前,僅僅執行了一步(id 10),是以此時count為1,當要求列印w的時候force執行了第二步(id 10),是以count增加為2。

4.28,當參數也是函數的時候,例如:

(define square (lambda(x) (* x x)))

(define (test proc a)

  (proc a))

(test square 3)

如果對operator不采用actual-value,那麼square将延時求值,在執行(proc a)時無法辨認eval的過程類型。

4.29,俺第一個想到的就是樹形遞歸的斐波那契數列:

(define (fib n)

  (cond ((= 0 n) 0)

            ((= 1 n) 1)

            (else

              (+ (fib (- n 1)) (fib (- n 2))))))

不帶記憶功能和帶記憶功能的force-it之間的性能差距非常明顯。

第二問,有趣的地方在于square過程,注意到(define (square x) (* x x)),x在body出現了兩次,那麼如果是使用不帶記憶功能的force-it, x将被求值兩次,如果x本身帶有副作用(例如例子裡面的id過程),那麼顯然副作用也将被調用兩次,是以答案不言自明。帶記憶功能的force-it版本中,count将仍然是1,而在不帶記憶功能的版本中count将增長到2。

4.30,第一問,我也談不出是以然為什麼ben的說法是正确的,關注下第二問的兩個過程在不同eval-sequence下的表現,(p1 1)的結果沒有改變都是(1 2),而(p2 1)在原始版本的eval-sequence中結果是1,而在cy修改後的版本中(對中間步驟采用actual-value)結果是(1 2),也就是說在原始版本中的(set! x (cons x '(2)))的副作用根本沒有實作,而在修改後的版本中實作了。俺覺的這個問題很迷惑,惰性求值與side effect互相作用很奇特,不過我更偏向原始版本,因為我覺的這樣的實作更容易看清代碼的意圖,也就是說在透明性上更好,例如我分析p2過程就可以認為直接傳回參數x;而實作副作用很容易讓人掉入陷阱,并且很可能引進難以查找的bug。

文章轉自莊周夢蝶  ,原文釋出時間2008-11-02