Advertisement
timothy235

sicp-3-3-5-propagation-of-constraints

Mar 2nd, 2017
165
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Racket 10.12 KB | None | 0 0
  1. #lang racket
  2. (require racket/mpair)
  3.  
  4. ;;;;;;;;;;;;;;;;
  5. ;; CONNECTORS ;;
  6. ;;;;;;;;;;;;;;;;
  7.  
  8. (define (make-connector)
  9.   (define value false)
  10.   (define informant false)
  11.   (define constraints empty)
  12.   (define (set-my-value newval setter)
  13.     (cond [(not (has-value? me))
  14.            (set! value newval)
  15.            (set! informant setter)
  16.            (for-each-except setter
  17.                             inform-about-value
  18.                             constraints)]
  19.           [(not (= value newval))
  20.            (error "Contradiction" (list value newval))]
  21.           [else 'ignored]))
  22.   (define (forget-my-value retractor)
  23.     (cond [(eq? retractor informant)
  24.            (set! informant false)
  25.            (for-each-except retractor
  26.                             inform-about-no-value
  27.                             constraints)]
  28.           [else 'ignored]))
  29.   (define (connect new-constraint)
  30.     (when (not (memq new-constraint constraints))
  31.       (set! constraints (cons new-constraint constraints)))
  32.     (when (has-value? me)
  33.       (inform-about-value new-constraint)
  34.       'done))
  35.   (define (me request)
  36.     (cond [(eq? request 'has-value?)
  37.            (if informant true false)]
  38.           [(eq? request 'value) value]
  39.           [(eq? request 'set-value!) set-my-value]
  40.           [(eq? request 'forget) forget-my-value]
  41.           [(eq? request 'connect) connect]
  42.           [else (error "Unknown operation -- CONNECTOR" request)]))
  43.   me)
  44.  
  45. (define (for-each-except exception procedure lst)
  46.   (map procedure (remove exception lst))
  47.   'done)
  48.  
  49. (define (has-value? connector) (connector 'has-value?))
  50. (define (get-value connector) (connector 'value))
  51. (define (set-value! connector new-value informant)
  52.   ((connector 'set-value!) new-value informant))
  53. (define (forget-value! connector retractor)
  54.   ((connector 'forget) retractor))
  55. (define (connect connector new-constraint)
  56.   ((connector 'connect) new-constraint))
  57.  
  58. ;;;;;;;;;;;;;;;;;
  59. ;; CONSTRAINTS ;;
  60. ;;;;;;;;;;;;;;;;;
  61.  
  62. (define (inform-about-value constraint)
  63.   (constraint 'I-have-a-value))
  64. (define (inform-about-no-value constraint)
  65.   (constraint 'I-lost-my-value))
  66.  
  67. (define (adder a1 a2 sum)
  68.   (define (process-new-value)
  69.     (cond [(and (has-value? a1) (has-value? a2))
  70.            (set-value! sum
  71.                        (+ (get-value a1) (get-value a2))
  72.                        me)]
  73.           [(and (has-value? a1) (has-value? sum))
  74.            (set-value! a2
  75.                        (- (get-value sum) (get-value a1))
  76.                        me)]
  77.           [(and (has-value? a2) (has-value? sum))
  78.            (set-value! a1
  79.                        (- (get-value sum) (get-value a2))
  80.                        me)]))
  81.   (define (process-forget-value)
  82.     (forget-value! sum me)
  83.     (forget-value! a1 me)
  84.     (forget-value! a2 me)
  85.     (process-new-value))
  86.   (define (me request)
  87.     (cond [(eq? request 'I-have-a-value)
  88.            (process-new-value)]
  89.           [(eq? request 'I-lost-my-value)
  90.            (process-forget-value)]
  91.           [else
  92.             (error "Unknown request -- ADDER" request)]))
  93.   (connect a1 me)
  94.   (connect a2 me)
  95.   (connect sum me)
  96.   me)
  97.  
  98. (define (multiplier m1 m2 product)
  99.   (define (process-new-value)
  100.     (cond [(or (and (has-value? m1) (zero? (get-value m1)))
  101.                (and (has-value? m2) (zero? (get-value m2))))
  102.            (set-value! product 0 me)]
  103.           [(and (has-value? m1) (has-value? m2))
  104.            (set-value! product
  105.                        (* (get-value m1) (get-value m2))
  106.                        me)]
  107.           [(and (has-value? product) (has-value? m1))
  108.            (set-value! m2
  109.                        (/ (get-value product) (get-value m1))
  110.                        me)]
  111.           [(and (has-value? product) (has-value? m2))
  112.            (set-value! m1
  113.                        (/ (get-value product) (get-value m2))
  114.                        me)]))
  115.   (define (process-forget-value)
  116.     (forget-value! product me)
  117.     (forget-value! m1 me)
  118.     (forget-value! m2 me)
  119.     (process-new-value))
  120.   (define (me request)
  121.     (cond [(eq? request 'I-have-a-value)
  122.            (process-new-value)]
  123.           [(eq? request 'I-lost-my-value)
  124.            (process-forget-value)]
  125.           [else
  126.             (error "Unknown request -- MULTIPLIER" request)]))
  127.   (connect m1 me)
  128.   (connect m2 me)
  129.   (connect product me)
  130.   me)
  131.  
  132. (define (constant value connector)
  133.   (define (me request)
  134.     (error "Unknown request -- CONSTANT" request))
  135.   (connect connector me)
  136.   (set-value! connector value me)
  137.   me)
  138.  
  139. (define (probe name connector)
  140.   (define (print-probe value)
  141.     (printf "Probe: ~a = ~a ~n" name value))
  142.   (define (process-new-value)
  143.     (print-probe (get-value connector)))
  144.   (define (process-forget-value)
  145.     (print-probe "?"))
  146.   (define (me request)
  147.     (cond [(eq? request 'I-have-a-value)
  148.            (process-new-value)]
  149.           [(eq? request 'I-lost-my-value)
  150.            (process-forget-value)]
  151.           [else
  152.             (error "Unknown request -- PROBE" request)]))
  153.   (connect connector me)
  154.   me)
  155.  
  156. ;;;;;;;;;;
  157. ;; 3.33 ;;
  158. ;;;;;;;;;;
  159.  
  160. (define (averager a b c)
  161.   (define s (make-connector))
  162.   (define t (make-connector))
  163.   (adder a b s)
  164.   (multiplier t c s)
  165.   (constant 2 t)
  166.   'ok)
  167.  
  168. ;; TEST
  169.  
  170. (define A (make-connector))
  171. (define B (make-connector))
  172. (define C (make-connector))
  173. (averager A B C)
  174. ;; 'ok
  175. (probe "A" A)
  176. ;; #<procedure:me>
  177. (probe "B" B)
  178. ;; #<procedure:me>
  179. (probe "C" C)
  180. ;; #<procedure:me>
  181.  
  182. (set-value! A 3 'user)
  183. ;; Probe: A = 3
  184. ;; 'done
  185. (set-value! B 5 'user)
  186. ;; Probe: B = 5
  187. ;; Probe: C = 4
  188. ;; 'done
  189. (forget-value! B 'user)
  190. ;; Probe: B = ?
  191. ;; Probe: C = ?
  192. ;; 'done
  193. (set-value! C 5 'user)
  194. ;; Probe: C = 5
  195. ;; Probe: B = 7
  196. ;; 'done
  197.  
  198. ;;;;;;;;;;
  199. ;; 3.34 ;;
  200. ;;;;;;;;;;
  201.  
  202. (define (bad-squarer a b)
  203.   (multiplier a a b)
  204.   'ok)
  205.  
  206. ;; TEST
  207.  
  208. (define E (make-connector))
  209. (define F (make-connector))
  210. (bad-squarer E F)
  211. ;; 'ok
  212. (probe "E" E)
  213. ;; #<procedure:me>
  214. (probe "F" F)
  215. ;; #<procedure:me>
  216. (set-value! E 3 'user)
  217. ;; Probe: E = 3
  218. ;; Probe: F = 9
  219. ;; 'done
  220. (forget-value! E 'user)
  221. ;; Probe: E = ?
  222. ;; Probe: F = ?
  223. ;; 'done
  224. (set-value! F 25 'user)
  225. ;; Probe: F = 25
  226. ;; 'done
  227.  
  228. ;; Clearing the value for a also clears the value for b.  If, after that, you set
  229. ;; the value for b, multiplier has no way to propagate the value back to a.
  230. ;; Multiplier expects to have two of three values in order to propagate to the
  231. ;; third, but here it has only one.  So no propagation occurs.
  232.  
  233. ;;;;;;;;;;
  234. ;; 3.35 ;;
  235. ;;;;;;;;;;
  236.  
  237. (define (squarer a b)
  238.   (define (process-new-value)
  239.     (cond [(has-value? b)
  240.            (if (negative? (get-value b))
  241.              (error "Square negative -- SQUARER" (get-value b))
  242.              (set-value! a (sqrt (get-value b)) me))]
  243.           [(has-value? a)
  244.            (set-value! b (sqr (get-value a)) me)]))
  245.   (define (process-forget-value)
  246.     (forget-value! b me)
  247.     (forget-value! a me)
  248.     (process-new-value))
  249.   (define (me request)
  250.     (cond [(eq? request 'I-have-a-value)
  251.            (process-new-value)]
  252.           [(eq? request 'I-lost-my-value)
  253.            (process-forget-value)]
  254.           [else
  255.             (error "Unknown request -- SQUARER" request)]))
  256.   (connect a me)
  257.   (connect b me)
  258.   me)
  259.  
  260. ;; TEST
  261.  
  262. (define G (make-connector))
  263. (define H (make-connector))
  264. (squarer G H)
  265. ;; #<procedure:me>
  266. (probe "G" G)
  267. ;; #<procedure:me>
  268. (probe "H" H)
  269. ;; #<procedure:me>
  270. (set-value! G 3 'user)
  271. ;; Probe: G = 3
  272. ;; Probe: H = 9
  273. ;; 'done
  274. (forget-value! G 'user)
  275. ;; Probe: G = ?
  276. ;; Probe: H = ?
  277. ;; 'done
  278. (set-value! H 25 'user)
  279. ;; Probe: H = 25
  280. ;; Probe: G = 5
  281. ;; 'done
  282.  
  283. ;; Here the constraint does give the square root as expected.
  284.  
  285. ;;;;;;;;;;
  286. ;; 3.36 ;;
  287. ;;;;;;;;;;
  288.  
  289. ;; Discuss the environments created by:
  290.  
  291. ;; (define a (make-connector))
  292. ;; (set-value! a 10 'user)
  293.  
  294. ;; make-connector is defined in the global environment.  So calling it creates a
  295. ;; binding frame E1 below the global environment.  It has no formal parameters to
  296. ;; bind, but it does create local definitions in E1, including set-my-value.
  297.  
  298. ;; set-value! is defined in the global environment.  Calling it on a, 10, and
  299. ;; 'user creates a binding frame E2, below the global environment, where connector
  300. ;; is bound to a (which is the me function in E1), new-value is bound to 10, and
  301. ;; informant is bound to 'user.  Then the body of set-value! is evaluated in E2.
  302.  
  303. ;; Evaluating the body of set-value! in E2 first calls connector a on 'set-value to
  304. ;; get the set-my-value function from E1, and then applies set-my-value to 10 and
  305. ;; 'user.
  306.  
  307. ;; Calling set-my-value creates a new binding frame E3 below E1, where newval is
  308. ;; bound to 10 and setter is bound to 'user.  Then its body is evaluated in E3,
  309. ;; and, as part of that, the for-each-except function is called.
  310.  
  311. ;; Calling for-each-except creates a new binding frame E4, below its enclosing
  312. ;; environment, which is the global environment.  Here in E4, the formal
  313. ;; parameters exception, procedure, and lst are bound to the setter,
  314. ;; inform-about-value, and constraints passed from E3.  Then the body of
  315. ;; for-each-except is run in E4, but this means calling inform-about-value on all
  316. ;; the constraints involving a.  Since the enclosing environment for
  317. ;; inform-about-value is E1, all these evaluations take place in binding frames
  318. ;; below E1 and thus have access to all a's local state.
  319.  
  320. ;;;;;;;;;;
  321. ;; 3.37 ;;
  322. ;;;;;;;;;;
  323.  
  324. (define (c+ x y)
  325.   (define z (make-connector))
  326.   (adder x y z)
  327.   z)
  328. (define (c* x y)
  329.   (define z (make-connector))
  330.   (multiplier x y z)
  331.   z)
  332. (define (c/ x y)
  333.   (define z (make-connector))
  334.   (multiplier y z x)
  335.   z)
  336. (define (cv value)
  337.   (define z (make-connector))
  338.   (constant value z)
  339.   z)
  340.  
  341. (define (celsius-fahrenheit-converter x)
  342.   (c+ (c* (c/ (cv 9) (cv 5))
  343.           x)
  344.       (cv 32)))
  345.  
  346. ;; TEST
  347.  
  348. (define C1 (make-connector))
  349. (define F1 (celsius-fahrenheit-converter C1))
  350. (probe "C1" C1)
  351. ;; #<procedure:me>
  352. (probe "F1" F1)
  353. ;; #<procedure:me>
  354. (set-value! C1 25 'user)
  355. ;; Probe: C1 = 25
  356. ;; Probe: F1 = 77
  357. ;; 'done
  358. (forget-value! C1 'user)
  359. ;; Probe: C1 = ?
  360. ;; Probe: F1 = ?
  361. ;; 'done
  362. (set-value! F1 212 'user)
  363. ;; Probe: F1 = 212
  364. ;; Probe: C1 = 100
  365. ;; 'done
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement