問題4.32-4.34

遅延評価リストとストリームについて。

4.32

ストリームと遅延リストの違いの例の一つとして、本文にも出てくるintegralが挙げられる。ストリームだと明示的にdelayとforceを使わないといけなかったが、遅延リストではその必要がない。
後は、carも遅延評価になるから、

;;; L-Eval input:
(define s (cons x t))
;;; L-Eval value:
ok

;;; L-Eval input:
s
;;; L-Eval value:
(compound-procedure (m) ((m x y)) <procedure-env>)

こんな風にしてもエラーにならない。

4.33

text-of-quotationは

(define (text-of-quotation exp) (cadr exp))

そうすると、cons,car,cdrの今回の定義のもとでは、(car '(a b c))は

(car '(a b c))
=> (car (list 'a 'b 'c))

みたいになるはずだけど、このlistは基盤Schemeのlistなので、今回のcons,car,cdrでは動かない。だから、今回はtext-of-quotationを導出された式として表現することが必要になるはず。

(car '(a b c))
=> (car (cons 'a (cons 'b (cons 'c '()))))

このような導出された式に変換する。で、これはこのままじゃだめで、評価しなきゃいけない。でもcons,car,cdrはdriver-loop上で定義してあるので、環境が必要。
評価にevalとactual-valueのどちらかを使うかだけど、この時点ではただのquoteの評価なので強制はしない方がいい。ということでevalを使う。

(define (text-of-quotation exp env)
  (define (rec lst)
    (if (null? lst)
        '()
        (list 'cons
              (list 'quote (car lst))
              (rec (cdr lst)))))
  (let ((body (cadr exp)))
    (if (not (pair? body)) body (eval (rec body) env))))

evalの方のtext-of-quotation呼び出しも変更しておく。これを使うと、

;;; L-Eval input:
(define (cons x y) (lambda (m) (m x y)))
;;; L-Eval value:
ok

;;; L-Eval input:
(define (car z) (z (lambda (p q) p)))
;;; L-Eval value:
ok

;;; L-Eval input:
(define (cdr z) (z (lambda (p q) q)))
;;; L-Eval value:
ok

;;; L-Eval input:
(car '(a b c))
;;; L-Eval value:
a

で、(car '(a b c))をちゃんと評価してくれる。

4.34

問題の解釈だけ。ちょっと遅延評価器で遊んでみます。

;;; L-Eval input:
(define (cons x y) (lambda (m) (m x y)))
;;; L-Eval value:
ok

;;; L-Eval input:
(define (car z) (z (lambda (p q) p)))
;;; L-Eval value:
ok

;;; L-Eval input:
(define (cdr z) (z (lambda (p q) q)))
;;; L-Eval value:
ok

;;; L-Eval input:
(define x (cons y z))
;;; L-Eval value:
ok

;;; L-Eval input:
(define y 0)
;;; L-Eval value:
ok

;;; L-Eval input:
(define z 1)
;;; L-Eval value:
ok

;;; L-Eval input:
x
;;; L-Eval value:
(compound-procedure (m) ((m x y)) <procedure-env>)

;;; L-Eval input:
(car x)
;;; L-Eval value:
0

;;; L-Eval input:
(cdr x)
;;; L-Eval value:
1

こんな風にいろいろ面白いことができるわけですが、単にxと入れたときにこれが合成手続きとして印字されてしまいます。これは遅延評価対と見たいわけなので、ほんとは(0 1)と表示されてほしいです。
また、(define ones (cons 1 ones))なんかは(1 1 1 1 1 1 ...)と永遠に続くリストなので、印字の際工夫する必要があります。
たぶん、無限リストの判別ができるようにして、遅延評価対と遅延リストに対するtagづけをして、driver-loop上でtagづけされた遅延評価対と遅延リストを強制すればできるような気がします。たぶん。難しそうなので省略。


ちょうどいいのでここまで。