--- /dev/null
+#lang racket
+
+#|
+
+The output is computed at that instant when the gate
+function is called. This value of the output is used
+by set-signal! during the required time segment. So,
+we don't compute the gate output at the time slot. It
+is already precomputed at definition time. So, we should
+also output them in the same order.
+
+|#
--- /dev/null
+#lang racket
+
+;; implementation
+(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 (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)
+ (newline)
+ (display "Probe: ")
+ (display name)
+ (display " = ")
+ (display 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 (inform-about-value constraint)
+ (constraint 'I-have-a-value))
+(define (inform-about-no-value constraint)
+ (constraint 'I-lost-my-value))
+
+(define (make-connector)
+ (let ((value #f) (informant #f) (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)
+ (when (not (memq new-constraint constraints))
+ (set! constraints
+ (cons new-constraint constraints)))
+ (when (has-value? me)
+ (inform-about-value new-constraint))
+ 'done)
+ (define (me request)
+ (cond ((eq? request 'has-value?)
+ (if informant #t #f))
+ ((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 (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) retractor))
+(define (connect connector new-constraint)
+ ((connector 'connect) new-constraint))
+
+;; averager
+(define (averager a b c)
+ (let ((u (make-connector))
+ (v (make-connector)))
+ (adder a b u)
+ (constant 0.5 v)
+ (multiplier u v c)))
+
+;; averager
+(define a (make-connector))
+(define b (make-connector))
+(define c (make-connector))
+
+(averager a b c)
+
+(probe "input 1" a)
+(probe "input 2" b)
+(probe "average" c)
+
+(define d (make-connector))
+(define e (make-connector))
+
+(define (squarer a b)
+ (multiplier a a b))
+
+(squarer d e)
+(probe "input to the squarer" d)
+(probe "squarer output" e)
--- /dev/null
+#lang racket
+
+#|
+
+If Louis Reasoner implements the squarer with a multiplier, like this:
+
+(define (squarer a b)
+ (multiplier a a b))
+
+let us see how we will use it.
+
+(define a (make-connector))
+(define b (make-connector))
+
+(set-value! a 10 'user)
+
+At this point, we expect b to have the value 100. Indeed it is. Now, instead
+we set the value of b to be 400. But multiplier needs two values to operate.
+We have set only b. So, the contraint never propagates to a. Here is the
+output of a repl session:
+
+> (set-value! e 400 'user)
+
+Probe: squarer output = 400
+'done
+>
+
+|#
\ No newline at end of file
--- /dev/null
+#lang racket
+
+;; implementation
+(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 (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)
+ (newline)
+ (display "Probe: ")
+ (display name)
+ (display " = ")
+ (display 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 (inform-about-value constraint)
+ (constraint 'I-have-a-value))
+(define (inform-about-no-value constraint)
+ (constraint 'I-lost-my-value))
+
+(define (make-connector)
+ (let ((value false) (informant #f) (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)
+ (when (not (memq new-constraint constraints))
+ (set! constraints
+ (cons new-constraint constraints)))
+ (when (has-value? me)
+ (inform-about-value new-constraint))
+ 'done)
+ (define (me request)
+ (cond ((eq? request 'has-value?)
+ (if informant #t #f))
+ ((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 (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) retractor))
+(define (connect connector new-constraint)
+ ((connector 'connect) new-constraint))
+
+(define (squarer a b)
+ (define (process-new-value)
+ (if (has-value? b)
+ (if (< (get-value b) 0)
+ (error "square less than 0 -- SQUARER" (get-value b))
+ (set-value! a
+ (sqrt (get-value b))
+ me))
+ (when (has-value? a)
+ (set-value! b
+ (* (get-value a) (get-value a))
+ me))))
+ (define (process-forget-value)
+ (forget-value! b me)
+ (forget-value! a 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 -- SQUARER" request))))
+ (connect a me)
+ (connect b me)
+ me)
+
+(define d (make-connector))
+(define e (make-connector))
+
+(squarer d e)
+
+(probe "input to the squarer" d)
+(probe "squarer output" e)
\ No newline at end of file
--- /dev/null
+#lang racket
+
+(define (celsius-fahrenheit-converter x)
+ (c+ (c* (c/ (cv 9) (cv 5))
+ x)
+ (cv 32)))
+(define C (make-connector))
+(define F (celsius-fahrenheit-converter C))
+
+(define (c+ a b)
+ (let ((c (make-connector)))
+ (adder a b c)
+ c))
+
+(define (c* x y)
+ (let ((z (make-connector)))
+ (multiplier x y z)
+ z))
+
+(define (cv v)
+ (let ((z (make-connector)))
+ (constant z v)
+ z))