計算機プログラムの構造と解釈 第二版 P226 問題4.13

束縛を解放する手続きunbind!を作りなさいという問題。
解放する手続きは今いるスコープの中のモノだけで良いと思う。つまりfirst-frameで取得できる所から消すだけでよい。そうじゃないと、他の手続きとかが使おうとしてたりするのに、勝手に消してしまうことになって、使えなくなる可能性がある。


実装ですが、ここまでにたような問題をやってきたそう復習みたいなもんだ。

  • evalに設定してもにゃもにゃやる
  • lookup-variableの応用で、見つけた後、削除するような手続きを作る。


実装

#!/usr/local/bin/gosh
;; -*- coding: utf-8 -*-

;;;実装
(load "./modules/4th.scm")
(load "./modules/let.scm")


(define (eval exp env)
  (cond ((self-evaluating? exp) exp)
        ((variable? exp) (lookup-variable-value exp env))
        ((quoted? exp) (text-of-quotation exp))
        ((assignment? exp) (eval-assignment exp env))
        ((definition? exp) (eval-definition exp env))
        ;;4.13
        ((unbind? exp) (eval-unbind exp env))

        ((if? exp) (eval-if exp env))
        ((lambda? exp)
         (make-procedure (lambda-parameters exp)
                         (lambda-body exp)
                         env))
        ((begin? exp) 
         (eval-sequence (begin-actions exp) env))
        ((cond? exp) (eval (cond->if exp) env))
        ;;4.6
        ((let? exp) (eval (let->combination exp) env))
        ((application? exp)
         (apply (eval (operator exp) env)
                (list-of-values (operands exp) env)))
        (else
          (error "Unknown expression type -- EVAL" exp))))


(define (unbind? exp) (tagged-list? exp 'unbind!))

(define (eval-unbind exp env)
  (unbind-variable! (unbind-varialbe exp) env)
  'ok)

(define (unbind-varialbe exp) (cadr exp))


(define (unbind-variable! var env)
  (let ((frame (first-frame env)))
    (define (scan vars vals)
      (cond ((null? vars)
             (error "Unbound variabl --UNBIND-VARIABLE:" var))
            ((eq? var (car vars))
             (set-car! vars (cadr vars))
             (set-cdr! vars (cddr vars))
             (set-car! vals (cadr vals))
             (set-cdr! vals (cddr vals)))
            (else (scan (cdr vars) (cdr vals)))))
    (scan (frame-variables frame)
          (frame-values frame))))


;;確認用
(define env1 (list (list (list 'a 'b 'c 'd) 1 2 3 4) (list (list 'a2 'b2 'c2 'd2) 1 2 3 4)))

(display "envの実態:")(print env1)
(display "(first-frame env1):")(print (first-frame env1))
(display "(frame-variables (first-frame env1)):")(print (frame-variables (first-frame env1)))
(display "(frame-values (first-frame env1)):")(print (frame-values (first-frame env1)))
(unbind-variable! 'c env1)
(display "(unbind-variable! 'c env1)のあとのenv1):")(print env1)


(define the-global-environment (setup-environment))
(driver-loop)


実行

envの実態:(((a b c d) 1 2 3 4) ((a2 b2 c2 d2) 1 2 3 4))
(first-frame env1):((a b c d) 1 2 3 4)
(frame-variables (first-frame env1)):(a b c d)
(frame-values (first-frame env1)):(1 2 3 4)
(unbind-variable! 'c env1)のあとのenv1):(((a b d) 1 2 4) ((a2 b2 c2 d2) 1 2 3 4))


;;; M-Eval input:
(define a 1)

;;; M-Eval value:
ok

;;; M-Eval input:
a

;;; M-Eval value:
1

;;; M-Eval input:
(unbind! a)

;;; M-Eval value:
ok

;;; M-Eval input:
a
gosh: "error": Unbound variable a

プロンプトが始まる前の部分はenvとかの確認です。