問題4-30
eval-sequence内で渡された式の並びに対して、一つずつactual-valueをしなければならないのではないかというCyの疑問について考えます。
aでBenが書いている手続きが、evalでも上手く動く理由としては、例え並びの要素がthunkされていたとしても、それ自身が式ならば、eval内のapplication?に引っかかり、そこで演算子がactual-valueされ、thunkタグが剥がれるので、式が正しく作用されるのではないかと考えられます。
しかし、bのp2の方の手続きは、evalだけでは上手くいきません。
(define (p2 x) (define (p e) e x) (p (set! x (cons x '(2))))) (p2 1)
こういう式があったら、結果は、(1 2)となってほしいところですが、evalバージョンだと(1)が返ってきてしまいます。その理由を考えてみると、p2の内部でpがdefineされた後、pが作用されますが、このときpの仮パラメータであるeに(set! x (cons x '(2)))がdelay-itされた上で束縛されます。その後、pの本体であるe->xという順に評価されるわけですが、この時それぞれの式はactual-valueではなく、ただのevalが実行されます。evalにeが渡されると、eは式ではなくvariableなので、束縛されている値をlookupするだけで終わってしまいます。つまり、束縛されているset!が評価される機会が発生しません。その結果、次のxが評価されて、xの束縛値である1が返ることになります。actual-valueを使っていれば、lookupされたeの束縛値に対してforce-itされるので、set!が評価され、xは(1 2)に更新されます。
cについては、eval-sequenceでactual-valueを使っても、force-itはthunkタグがなければそのまま渡された値を返すだけなので、遅延オブジェクトでなければevalと動きは変わらないのではと思います。
dの考察と、問題4-31は飛ばしました。