SICP 問題 4.30
並びの中の式は最後まで評価されないのではないかというCy D. Fectの心配に答える.
a
;; 元のeval-sequence (define (eval-sequence exps env) (cond ((last-exp? exps) (eval (first-exp exps) env)) (else (eval (first-exp exps) env) (eval-sequence (rest-exps exps) env)))) ;; Cy D.Fectが提案したeval-sequence (define (eval-sequence exps env) (cond ((last-exp? exps) (eval (first-exp exps) env)) (else (actual-value (first-exp exps) env) (eval-sequence (rest-exps exps) env))))
;;; M-Eval input: (define (for-each proc items) (if (null? items) 'done (begin (proc (car items)) (for-each proc (cdr items))))) ;;; M-Eval value: ok ;;; M-Eval input: (for-each (lambda (x) (newline) (display x)) '(57 321 88)) 57 321 88 ;;; M-Eval value: done
初めのbeginで以下の式になる.
(begin ((lambda (x) (newline) (display x)) 57) (for-each (lambda (x) (newline) (display x)) '(321 88)))
beginの一つ目の式では(newline)はそのままevalされてM-Eval inputに空行が印字される.
二つ目の式は(display x)で,このxに(thunk 57)が入るが,displayは基本式なのでforceされ57になる.
そして57が印字される.
これを繰り返すのでfor-eachは正しく動く.
b
;;; M-Eval input: (define (p1 x) (set! x (cons x '(2))) x) ;;; M-Eval value: ok ;;; M-Eval input: (define (p2 x) (define (p e) e x)) ;;; M-Eval value: ok ;;; M-Eval input: (define (p2 x) (define (p e) e x) (p (set! x (cons x '(2))))) ;;; M-Eval value: ok
本文のeval-sequenceではp1のset!は基本手続きなので実行される.
p2のpは複合手続きなので遅延され実行されない.
;;; M-Eval input: (p1 1) ;;; M-Eval value: (1 2) ;;; M-Eval input: (p2 1)
Cyの提案するeval-sequenceの場合
;;; M-Eval input: (p1 1) ;;; M-Eval value: (1 2) ;;; M-Eval input: (p2 1) ;;; M-Eval value: (1 2)
c aでやったfor-eachの振る舞いはCyのeval-sequenceでも変わらない. aの式では基本手続きを使うために遅延されない. Cyの式では強制的に評価するため遅延されない.
d ググってみた感じでは直列化して,最後の式が必要になったタイミングで他の式も強制的に評価するのがいいと思いました. 読んだのはこちら↓