SICP 4.3.3 Ex. 4.51

  • 投稿日:
  • カテゴリ:

Ex. 4.51

p.257 analyze-assignment を改造する。失敗継続に埋め込まれている環境の巻き戻し処理を取り去ればよい。

(define (permanent-assignment? exp)  ;; 追加
  (tagged-list? exp 'permanent-set!))

;; p.257 analyze-assignmentとほとんど同じ
(define (analyze-permanent-assignment exp) ;; 追加
  (let ((var (assignment-variable exp))
        (vproc (analyze (assignment-value exp))))
    (lambda (env succeed fail)
      (vproc env
             (lambda (val fail2)        ; *1*
               (let ((old-value
                      (lookup-variable-value var env))) 
                 (set-variable-value! var val env)
                 (succeed 'ok
                          (lambda ()    ; *2*  ;; このλは失敗継続
                            ;;; 環境の巻き戻し処理を消すだけ
                            ;;;(set-variable-value! var
                        ;;;                     old-value
                        ;;;                     env)
                            (fail2)))))
             fail))))

;; p.234 analyze
(define (analyze exp)
  (cond ((self-evaluating? exp) 
        ...
        ((permanent-assignment? exp) (analyze-permanent-assignment exp)) ;; 追加
        ...

permanent-set! の代わりに set! を使うと、(a b 1), (a c 1), ... と常に1 が返る。バックアップ、バックトラックするたびに count の値の変更が巻き戻されて 0 に戻るから。

permanent-set! をつかうと (amb 1 2 3) の引数の合計 6 を求めたりもできる。

しかし、この手の機能は、ストリーム処理で十分こなせる。また、ストリームで処理すべきである。permanent-set!みたいな機能を入れるなら、わざわざ継続を使って amb の実装をした意味がない。