Ex. 4.32
遅延度が高いというのは、cons の第1引数が遅延することを指す。3章のストリームでは、これは遅延されない。3章ストリームで遅延されるのはcons の第2引数のみである。
例1. 未知数のストリームが作れる。
(x x x x x ...)
こういうの。3章ストリームだと
(define xs (cons-stream x xs))
x の未定義エラーになる。cons-stream は第1引数の x を評価するからだ。 遅延ストリームだと
(define xs (cons x xs))
エラーにならない。遅延ストリームの cons はどちらの引数も遅延するからだ。
例2. ネストが無限のリストが作れる。
((((...(1)...1) 1) 1) 1)
こういうの。3章ストリームだと
(define ones2 (cons-stream ones2 '(1)))
ones2 の未定義エラーになる。cons-stream は第1引数の ones2 を評価するからだ。 遅延ストリームだと
(define ones2 (cons ones2 '(1)))
エラーにならない。遅延ストリームの cons はどちらの引数も遅延するからだ。
Ex. 4.33
方針: ペアのクォートは cons 式で置き換えてから評価して返す。
'(a b) → (eval (cons 'a (cons 'b '())) the-global-environment)
という感じ。
アトムのクォートはそのまま返す。
'a → a '1 → 1 '() → ()
という感じ。実装は
;; convert a quoted pair into cons expression and then eval it,
;; on the other hand a quoted atom return itself.
(define (text-of-quotation exp env)
(let ((e (cadr exp)))
(if (pair? e)
(eval (quote->cons e) env) ;;; quoted pair is converted to cons and evaled
e))) ;;; quoted atom returns itsef
;; convert a pair into cons expression
;; like this
;; (a b) -> (cons 'a (cons 'b '()))
;; convert an atom as quoted
;; a -> 'a
;; 1 -> '1
;; () -> '()
(define (quote->cons exp)
(if (pair? exp)
(list 'cons (quote->cons (car exp)) (quote->cons (cdr exp)))
(list 'quote exp)))
(define (eval exp env)
...
((variable? exp)(lookup-variable-value exp env))
((quoted? exp) (text-of-quotation exp env)) ;; changed
((assignment? exp)(eval-assignment exp env))
...
アトムのクォートの処理がどんくさくて微妙。
Ex. 4.34
まず (cons 1 2) の評価結果は、
(compound-procedure (m) ((m x y)) <procedure-env>) ← ①
となる。procedure として返ってくる。cons を lambda に変換しているのだから当然である。 で、これを印字するときだけ (1 2) としたいわけであるが、、、
まずこの procedure を他の procedure と区別する方法がない。ので何か区別をつける工夫をしてやらねばならない。
面倒なので、あまり正しくない方法であるが、仮引数 m を $cons とかにして仮引数の名前で区別することにする。
次に表示のためにリストの car と cdr を取得せねばならないが、これは ①に car, cdr を apply して取り出すこととする。
あと、無限リストの対応は、面倒なので、リストを10個表示したら、そこで中止するくらい。
以上の方針で、実装しようとしましたが失敗しました。
修正途中のソースは以下のとおり。
;; This doesn't work at all.
(define (user-print object)
(if (compound-procedure? object)
(if (cons-procedure? object) ;;; changed
(display (actual-value (apply (actual-value 'car the-global-environment) object the-global-environment)) the-global-environment) ;;; changed
(display (list 'compound-procedure
(procedure-parameters object)
(procedure-body object)
'<procedure-env>)))
(display object)))
(define (cons-procedure? obj)
(eq? (caadr obj) '$cons))
あと、子Scheme のcons の定義も変える
;;; L-Eval value:
(define (cons x y)
(lambda ($cons) ($cons x y))) the-global-environment)
仮引数を m から $cons に変えた。
以上、とりあえずリストの car だけ表示させるつもりで作ったのですが、全然動きません、、、orz、疲れたので 退却~。(^^ゞ