exercise 4.18

続き

ex4.18

やってみる前に解答。
4.18の例だと、dyの定義時にyが*unassigned*でエラー。
ようするに、この例だと、内部定義を相互に行えないというかなんというか。

まぁということで実行してみるか。
まず、delayとかの準備

(define (delay-exp exp) (cadr exp))
;;メモ化無しver
;;(define (delay->lambda exp) (make-lambda '() (list (delay-exp exp))))
(define (delay->memo-lambda exp)
  (list 'memo-proc (make-lambda '() (list (delay-exp exp)))))
(put 'eval 'delay (lambda (exp env)
                    (eval (delay->memo-lambda exp) env)))
                    
(define (cons-stream->combination exp)
  (list 'cons (cadr exp) (list 'delay (caddr exp))))
(put 'eval 'cons-stream
     (lambda (exp env)
       (eval (cons-stream->combination exp) env)))

で、こんどは以下のコードを(driver-loop)のあとに読みこませる。
読みこませるのはEmacsで、C-x h で選択後、C-c C-rとやればおk。
(・・・でいいよね)

(define (memo-proc proc)
  (let ((already-run false) (result false))
    (lambda ()
      (if (not already-run)
          (begin (set! result (proc))
                 (set! already-run true)
                 result)
          result))))


(define the-empty-stream '())

(define (stream-null? s)
  (eq? s the-empty-stream))

(define (stream-car stream) (car stream))
(define (stream-cdr stream) (force (cdr stream)))

(define (force delayed-object)
  (delayed-object))

(define (stream-map proc s)
  (if (stream-null? s)
      the-empty-stream
      (cons-stream (proc (stream-car s))
                   (stream-map proc (stream-cdr s)))))

(define (stream-map2 proc s1 s2)
  (if (stream-null? s1)
      the-empty-stream
      (cons-stream (proc (stream-car s1)(stream-car s2))
                   (stream-map2 proc (stream-cdr s1)(stream-cdr s2)))))

(define (stream-ref s n)
  (if (= n 0)
      (stream-car s)
      (stream-ref (stream-cdr s) (- n 1))))

(define (scale-stream stream factor)
  (stream-map (lambda (x) (* x factor)) stream))

(define (add-streams s1 s2)
  (stream-map2 + s1 s2))


(define (integral delayed-integrand initial-value dt)
  (define int
    (cons-stream initial-value
                 (let ((integrand (force delayed-integrand)))
                   (add-streams (scale-stream integrand dt)
                                int))))
  int)

(define (solve f y0 dt)
  (define y (integral (delay dy) y0 dt))
  (define dy (stream-map f y))
  y)

;;変更後のlet

(define alphabets-list '(a b c d e f g h i j k l m n))
(define (scan-out-defines body)
  (define (iter vars vals alphabets body-remainig alphabets-remaining)
    (let ((first (first-exp body-remainig)))
      (if (or (not (pair? first)) (not (eq? 'define (car first))))
          (if (null? vars)
              body-remainig
              (let ((vars (reverse vars))
                    (vals (reverse vals))
                    (alphabets (reverse alphabets)))
                (list
                 (make-let
                  (map (lambda (var) (list var ''*unassigned*)) vars)
                  (append
                   (list
                   (make-let
                    (map (lambda (alp val) (list alp val)) alphabets vals)
                    (map (lambda (var alp) (list 'set! var alp)) vars alphabets)))
                   body-remainig)))))
          (iter (cons (definition-variable first) vars)
                (cons (definition-value first) vals)
                (cons (car alphabets-remaining) alphabets)
                (rest-exps body-remainig)
                (cdr alphabets-remaining)))))
    (iter '() '() '() body alphabets-list))

もうなんかスゲー適当感がただようぜ・・・
以下は scan-out-defines の例

> (scan-out-defines '((define u e1) (define v e2) e3))
((let ((u (quote *unassigned*)) (v (quote *unassigned*))) (let ((a e1) (b e2)) (set! u a) (set! v b)) e3))

で、結果。(let変更なし)

;;; M-Eval input:
(stream-ref (solve (lambda (y) y) 1 0.01) 100)

;;; M-Eval value:
2.704813829421526

;;; M-Eval input:
(stream-ref (solve (lambda (y) y) 1 0.001) 1000)

;;; M-Eval value:
2.716923932235896

という風に一応最初の例では動いてますな。
なんかちょっと感動した。
ちなみに実家で使っていたEeePCくんではメモ化ありだとエラーがでました。
引数がながすぎると怒られた気がする。


ちなみにletをいじくった場合は以下

;;; M-Eval input:
(stream-ref (solve (lambda (y) y) 1 0.01) 100)
Unbound variable y

とまぁ予想どおり