SICP 4.2.3 Ex. 4.32 Ex. 4.33 Ex. 4.34

  • 投稿日:
  • カテゴリ:

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、疲れたので 退却~。(^^ゞ