exercise 4.29~31
exercise 4.29
(square (id 10))
はメモ化に関わらず100
countはメモ化有りだと1、無しだと2。
squareの中で(* x x)ってなってるので、メモ化しないと(id 10)が2回計算されるんです
な。
exercise 4.30
a.うまく説明できないけど、newlineもdisplayもprimitiveだし普通に考えれ
ば動くよね・・・。あーどう言えばいいんだろうか。
b.確かにこういう場合は揉めるよね
もとの場合
;;; L-Eval input: (p1 1) ;;; L-Eval value: (1 2) ;;; L-Eval input: (p2 1) ;;; L-Eval value: 1
Cyの場合
;;; L-Eval input: (p1 1) ;;; L-Eval value: (1 2) ;;; L-Eval input: (p2 1) ;;; L-Eval value: (1 2)
もとの場合だと、p2の引数の(set! x (cons x '(2)))がthunkになってしまい、
その後、p内でeが呼ばれたときはevalの中でvariable?にかかって
lookup-variable-valueされて、結局(thunk ...)という結果が返るがそこまで。
thunkなまんま。ちなみにxの方は返ったあとにdriver-loopでactual-valueを
求められるので問題無し。
Cyの場合だと、p2のpが呼ばれ、eはactual-valueに渡されthunkから復帰(って
言うのか?)まぁそんなこんなでうまくいくと。
ダメだ。さっぱり上手く説明できた気がしない。
c.そりゃうまくいくだろう。というか当たり前すぎて説明できん。どう言った
ものか。
d.Cyの方が正しい結果になるんだろうが、なんだかなー。
もういっそ副作用を用いないようにコードを書けば・・・
ってこれは問題の趣旨から外れるか。
exercise 4.31
make-procedureとかに変更は無し。
parametersからpatameterの名前とlazyかどうかのリストを分離して、動作を
分けた。
以外にサクっとできたけどいいのかしら。
(define (apply-gosh procedure arguments env) (cond ((primitive-procedure? procedure) (apply-primitive-procedure procedure (list-of-arg-values arguments env))) ((compound-procedure? procedure) (eval-sequence (procedure-body procedure) (extend-environment (list-of-arg-names (procedure-parameters procedure)) ;ここらへんから変更 (list-of-delayed-args-and-values arguments (list-of-lazy-or-not (procedure-parameters procedure)) env) (procedure-environment procedure)))) (else (error "Unknown procedure type -- APPLY" procedure)))) ;;こっから演習用のやつ (define (list-of-arg-names parameters) ;;argじゃなくてparameterだなぁ (map (lambda (x) (if (pair? x) (car x) x)) parameters)) (define (list-of-lazy-or-not parameters) (map (lambda (x) (if (pair? x) (cadr x) 'not-lazy)) parameters)) (define (list-of-delayed-args-and-values exps lazy-check-list env) (map (lambda (exp check) (cond ((eq? check 'not-lazy) (actual-value exp env)) ((eq? check 'lazy) (delay-it exp env)) ((eq? check 'lazy-memo) (delay-it-memo exp env)) (else (error "Unknown declaration " check)))) exps lazy-check-list)) ;;forceはひとまとめに (define (force-it obj) (cond ((thunk? obj) (actual-value (thunk-exp obj) (thunk-env obj))) ((thunk-memo? obj) (let ((result (actual-value (thunk-exp obj) (thunk-env obj)))) (set-car! obj 'evaluated-thunk) (set-car! (cdr obj) result) ; replace exp with its value (set-cdr! (cdr obj) '()) ; forget unneeded env result)) ((evaluated-thunk? obj) (thunk-value obj)) (else obj))) ;; thunks (define (delay-it exp env) (list 'thunk exp env)) (define (delay-it-memo exp env) (list 'thunk-memo exp env)) (define (thunk? obj) (tagged-list? obj 'thunk)) (define (thunk-memo? obj) (tagged-list? obj 'thunk-memo))
あいかわらずのネーミングの怪しさ。なんか気になる。
まぁそれはそうと動作は以下。
適当な副作用を返す関数を使ってチェックしている・・・つもり。
;;; L-Eval input: (define (square n) (* n n)) ;;; L-Eval value: ok ;;; L-Eval input: (square 10) ;;; L-Eval value: 100 ;;; L-Eval input: (define (hello-and-return-5) (display "hello") (newline) 5) ;;; L-Eval value: ok ;;; L-Eval input: (define (square (n lazy)) (* n n)) ;;; L-Eval value: ok ;;; L-Eval input: (square (hello-and-return-5)) hello hello ;;; L-Eval value: 25 ;;; L-Eval input: (define (square (n lazy-memo)) (* n n)) ;;; L-Eval value: ok ;;; L-Eval input: (square (hello-and-return-5)) hello ;;; L-Eval value: 25 ;;; L-Eval input: (define (take-latter-value x y) y) ;;; L-Eval value: ok ;;; L-Eval input: (take-latter-value (hello-and-return-5) 10) hello ;;; L-Eval value: 10 ;;; L-Eval input: (define (take-latter-value (x lazy) y) y) ;;; L-Eval value: ok ;;; L-Eval input: (take-latter-value (hello-and-return-5) 10) ;;; L-Eval value: 10
とまぁいけてる感じがする。感じが。