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

とまぁいけてる感じがする。感じが。