2014年7月12日土曜日

開発環境

計算機プログラムの構造と解釈[第2版](ハロルド エイブルソン (著)、ジュリー サスマン (著)、ジェラルド・ジェイ サスマン (著)、Harold Abelson (原著)、Julie Sussman (原著)、Gerald Jay Sussman (原著)、和田 英一 (翻訳)、翔泳社、原書: Structure and Interpretation of Computer Programs (MIT Electrical Engineering and Computer Science)(SICP))の3(標準部品化力、オブジェクトおよび状態)、3.3(可変データでのモデル化)、3.3.5(制約の拡散)、制約システムの使い方、制約システムの実装、コネクタの表現、問題 3.33.を解いてみる。

その他参考書籍

問題 3.33.

コード(BBEdit, Emacs)

constraint_system.scm

;; -*- coding: utf-8 -*-

(define (has-value? connector)
  (connector 'has-value?))
(define (get-value connector)
  (connector 'value))
(define (set-value! connector new-value informant)
  ((connector 'set-value) new-value informant))
(define (forget-value! connector retractor)
  ((connector 'forget-value!) retractor))
(define (connect connector new-constraint)
  ((connector 'connect) new-constraint))

(define (adder a1 a2 sum)
  (define (process-new-value)
    (cond ((and (has-value? a1) (has-value? a2))
           (set-value! sum
                       (+ (get-value a1) (get-value a2))
                       me))
          ((and (has-value? a1) (has-value? sum))
           (set-value! a2
                       (- (get-value sum) (get-value a1))
                       me))
          ((and (has-value? a2) (has-value? sum))
           (set-value a1
                      (- (get-value sum) (get-value a2))
                      me))))
  (define (process-forget-value)
    (forget-value! sum me)
    (forget-value! a1 me)
    (forget-value! a2 me)
    (process-new-value))
  (define (me request)
    (cond ((eq? request 'I-have-a-value)
           (process-new-value))
          ((eq? request 'I-lost-my-value)
           (process-forget-value))
          (else
           (error "Unknown request -- ADDER" request))))
  (connect a1 me)
  (connect a2 me)
  (connect sum me)
  me)

(define (inform-about-value constraint)
  (constraint 'I-have-a-value))
(define (inform-about-no-value constraint)
  (constraint 'I-lost-my-value))

(define (multiplier m1 m2 product)
  (define (process-new-value)
    (cond ((or (and (has-value? m1) (= (get-value m1) 0))
               (and (has-value? m2) (= (get-value m2) 0)))
           (set-value! product 0 me))
          ((and (has-value? m1) (has-value? m2))
           (set-value! product
                       (* (get-value m1) (get-value m2))
                       me))
          ((and (has-value? product) (has-value? m1))
           (set-value! m2
                       (/ (get-value product) (get-value m1))
                       me))
          ((and (has-value? product) (has-value? m2))
           (set-value! m1
                       (/ (get-value product) (get-value m2))
                       me))))
  (define (process-forget-value)
    (forget-value! product me)
    (forget-value! m1 me)
    (forget-value! m2 me)
    (process-new-value))
  (define (me request)
    (cond ((eq? request 'I-have-a-value)
           (process-new-value))
          ((eq? request 'I-lost-my-value)
           (process-forget-value))
          (else
           (error "Unknown request -- MULTIPLIER" request))))
  (connect m1 me)
  (connect m2 me)
  (connect product me)
  me)

(define (constant value connector)
  (define (me request)
    (error "Unknown request -- CONSTANT" request))
  (connect connector me)
  (set-value! connector value me)
  me)

(define (probe name connector)
  (define (print-probe value)
    (print "Probe: " name " = " value))
  (define (process-new-value)
    (print-probe (get-value connector)))
  (define (process-forget-value)
    (print-probe "?"))
  (define (me request)
    (cond ((eq? request 'I-have-a-value)
           (process-new-value))
          ((eq? request 'I-lost-my-value)
           (process-forget-value))
          (else
           (error "Unknown request -- PROBE" request))))
  (connect connector me)
  me)
           
(define (make-connector)
  (let ((value false)
        (informant false)
        (constraints '()))
    (define (set-my-value newval setter)
      (cond ((not (has-value? me))
             (set! value newval)
             (set! informant setter)
             (for-each-except setter
                              inform-about-value
                              constraints))
            ((not (= value newval))
             (error "Contradiction" (list value newval)))
            (else 'ignored)))
    (define (forget-my-value retractor)
      (if (eq? retractor informant)
          (begin (set! informant false)
                 (for-each-except retractor
                                  inform-about-no-value
                                  constraints))
          'ignored))
    (define (connect new-constraint)
      (if (not (memq new-constraint constraints))
          (set! constraints
                (cons new-constraint constraints)))
      (if (has-value? me)
          (inform-about-value new-constraint))
      'done)
    (define (me request)
      (cond ((eq? request 'has-value?)
             (if informant true false))
            ((eq? request 'value) value)
            ((eq? request set-value!) set-my-value)
            ((eq? request 'forget) forget-my-value)
            ((eq? request 'connect) connect)
            (else (error "Unknown operation -- CONNECTOR" request))))
    me))

(define (for-each-except exception procedure list)
  (define (loop items)
    (cond ((null items) 'done)
          ((eq? (car items) exception) (loop (cdr items)))
          (else (procedure (car items))
                (loop (cdr items)))))
  (loop list))

(define (average a b c)
  (define (process-new-value)
    (cond ((and (has-value? a) (has-value? b))
           (set-value c
                      (/ (+ (get-value a) (get-value b)) 2)
                      me))
          ((and (has-value? a) (has-value? c))
           (set-value b
                      (- (* 2 (get-value c)) a)
                      me))
          ((and (has-value? b) (has-value? c))
           (set-value a
                      (- (* 2 (get-value c)) b)
                      me))))
  (define (process-forget-value)
    (forget-value! c)
    (forget-value! a)
    (forget-value! b)
    (process-new-value))
  (define (me request)
    (cond ((eq? request 'I-have-a-value)
           (process-new-value))
          ((eq? request 'I-LOST-MY-VALUE)
           (process-new-value))
          (else
           (error "Unknown request -- AVERAGE" request))))
  (connect a me)
  (connect b me)
  (connect c me)
  me)

sample3_33.scm

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

(load "./constraint_system.scm")

(define a (make-connector))
(define b (make-connector))
(define c (make-connector))

(probe 'a a)
(probe 'b b)
(probe 'c c)

(average a b c)

(for-each (lambda (connector)
            (print a "has-value?: " (has-value? connector)))
          (list a b c))

(for-each (lambda (connector)
            (print a "get-value: " (get-value connector)))
          (list a b c))

(set-value! a 5 'user1)
(set-value! b 10 'user2)

(print '(forget-value! a 'user3))
(print (forget-value! a 'user3))
(print '(forget-value! a 'user1))
(print (forget-value! a 'user1))
(print '(set-value! c 15/2 'user4))
(print (set-value! c 15/2 'user4))

入出力結果(Terminal(gosh), REPL(Read, Eval, Print, Loop))

$ ./sample3_33.scm 
#<closure (make-connector me)>has-value?: #f
#<closure (make-connector me)>has-value?: #f
#<closure (make-connector me)>has-value?: #f
#<closure (make-connector me)>get-value: #f
#<closure (make-connector me)>get-value: #f
#<closure (make-connector me)>get-value: #f
Probe: a = 5
Probe: c = 15/2
Probe: b = 10
(forget-value! a 'user3)
ignored
(forget-value! a 'user1)
Probe: c = ?
Probe: a = ?
done
(set-value! c 15/2 'user4)
Probe: a = 5
Probe: c = 15/2
done
$

0 コメント:

コメントを投稿