SICP 4.1.7-4.2.1
4.22
問題4.6では、 let->combinationを実装することで実現している。 ここでも同じアプローチを使う。
let->combination は 4.6 で定義済みなので、 analyze手続きに 以下を追記する
(define (analyze exp) (cond ((self-evaluating? exp) (analyze-self-evaluating exp)) ;;(中略) ((let? exp) (analyze (let->combination exp))) ;; 追記 ((application? exp) (analyze-application exp)) (else (error "Unknown expression type -- ANALYZE" exp))))
4.23
本文の定義
(define (analyze-sequence exps) (define (sequentially proc1 proc2) (lambda (env) (proc1 env) (proc2 env))) (define (loop first-proc rest-procs) (if (null? rest-procs) first-proc (loop (sequentially first-proc (car rest-procs)) (cdr rest-procs)))) (let ((procs (map analyze exps))) (if (null? procs) (error "Empty sequence -- ANALYZE")) (loop (car procs) (cdr procs))))
Alyssaの定義
(define (analyze-sequence exps) (define (execute-sequence procs env) (cond ((null? (cdr procs)) ((car procs) env)) (else ((car procs) env) (execute-sequence (cdr procs) env)))) (let ((procs (map analyze exps))) (if (null? procs) (error "Empty sequence -- ANALYZE")) (lambda (env) (execute-sequence procs env))))
並びが一つの場合
本文の実装
loop に評価される rest-procs がnilになる。 そのため、 first-procそのものが返ってくる。
alyssaの実装
lambda式 (lambda (env) (execute-sequence procs env)) が返ってくる
並びが2つの場合
本文の実装
説明しにくいが、 loopによって 順次 sequectially 手続きが適用された lambda 式が返ってくる 要は 各式に対して (loop (sequentially first-proc (car rest-procs)) (cdr rest-procs)))) によって、 (lambda (env) (proc1 env) (proc2 env))) が順次適用された結果が返ってくる。
alyssaの実装
1つの場合と同じなので、 式のリスト(procs)が含まれた lambda式 (lambda (env) (execute-sequence procs env)) が返ってくる
2つの比較
まとめると、 本文の実装は
(begin <procA> <procB> <procC>)
のような入力に対して、
(lambda (env) (lambda (env) (lambda (env) (<eval-procA> env)) (<eval-procB> env)) (<eval-procC> env))
という手続きが作られる。
Alyssaの場合は
(labmda (env) (execute-sequence (list (lambda (env) (<eval-procA> env)) (lambda (env) (<eval-procB> env)) (lambda (env) (<eval-procC> env)))))
という手続きになる。 この結果、個々のシーケンスの解釈が実行時に都度行われてしまう。
つまり本文にある
lambda式の解析は, 効率に大きな利益をもたらす: lambdaの評価の結果の手続きが多数回作用されようとも, lambda本体は一回だけ解析される.
この恩恵が失われてしまうことになる。
4.24
試してないが、未分離のモノより分離したモノの方が、構文解析の処理が減る分早くなるはず。
4.25
停止しない。
作用的順序では n=1の場合にも (factorial (- n 1)) を評価してしまうため、再帰が終わらない。
正規順序の場合、 n=1 のときには (factorial (- n 1)) が評価されないので、正常動作する。
4.26
unless->if を作って実装する
; analyze に ((unless? exp) (analyze (unless->if exp))) を追加 (define (unless? exp) (tagged-list? exp 'unless)) ;;(unless condition usual-value exceptional-value) (define (unless-condition exp) (cadr exp)) (define (unless-usual-value exp) (caddr exp)) (define (unless-exceptional-value exp) (if (null? (cdddr exp)) #f ;; exceptional-valueを省略した場合 (cadddr exp))) ;;(unless condition usual-value exceptional-value) ;; -> (if condition exceptional-value usual-value) (define (unless->if exp) (make-if (unless-condition exp) (unless-exceptional-value exp) (unless-usual-value exp)))