SICP 読み (157) 4.1.2 式の表現

昨晩の続き。

(set! x ((lambda (x) (+ x 1)) x))

の評価について。x は大域環境で 1 に束縛されているのが前提で。
まず、このリストは eval にて assignment? が true と判断。なので eval-assignment に環境とリストが渡される。

(eval-assignment '(set! x ((lambda (x) (+ x 1)) x)) env)

そん中でどうなるか、というと以下。

  (set-variable-value! (assignment-variable exp)
		       (eval (assignment-value exp) env)
		       env)

引数を当てはめてみるとこうなる。

  (set-variable-value! (assignment-variable '(set! x ((lambda (x) (+ x 1)) x)))
                       (eval (assignment-value '(set! x ((lambda (x) (+ x 1)) x))) env)
                       env)

assignment-* がナニされて以下。

  (set-variable-value! 'x (eval '((lambda (x) (+ x 1)) x) env) env)

順番として先に eval で始まるリストがナニ。これは eval で application と評価されて apply に渡される。こんなカンジでしょうか。

(apply (eval '(lambda (x) (+ x 1)) newenv)
       (list-of-values '(x) newenv))

これはこの環境では 2 と評価されるので、set-variable-value! が x の束縛は見つけて 2 を設定する、という若干ハショッたナニで解決。

束縛 (definition)

set と define の違いを見ると面白い。

(define (set-variable-value! var val env)
  (define (env-loop env)
    (define (scan vars vals)
      (cond ((null? vars)
	     (env-loop (enclosing-environment env)))
	    ((eq? var (car vars))
	     (set-car! vals val))
	    (else (scan (cdr vars) (cdr vals)))))
    (if (eq? env the-empty-environment)
	(error "Unbound variable -- SET!" var)
	(let ((frame (first-frame env)))
	  (scan (frame-variables frame)
		(frame-values frame)))))
  (env-loop env))

(define (define-variable! var val env)
  (let ((frame (first-frame env)))
    (define (scan vars vals)
      (cond ((null? vars)
	     (add-binding-to-frame! var val frame))
	    ((eq? var (car vars))
	     (set-car! vals val))
	    (else (scan (cdr vars) (cdr vals)))))
    (scan (frame-variables frame)
	  (frame-values frame))))

何が違う、と言うと

  • set は束縛を大域環境まで探索。大域環境に定義が無ければエラー。
  • define はカレントな環境しか見ない。カレントな環境に束縛が無ければ定義してしまう。

なんか調子悪い、が言いわけにならん位の質の低さだな。練習問題 4.11 とかにとりかかった方が前向きな気もしています。とりあえずヤリたい放題なスペースなんで方向転換ありかも。(を