diff options
author | elioat <elioat@tilde.institute> | 2023-08-23 07:52:19 -0400 |
---|---|---|
committer | elioat <elioat@tilde.institute> | 2023-08-23 07:52:19 -0400 |
commit | 562a9a52d599d9a05f871404050968a5fd282640 (patch) | |
tree | 7d3305c1252c043bfe246ccc7deff0056aa6b5ab /js/games/nluqo.github.io/~bh/61a-pages/Lib/chapter3.code | |
parent | 5d012c6c011a9dedf7d0a098e456206244eb5a0f (diff) | |
download | tour-562a9a52d599d9a05f871404050968a5fd282640.tar.gz |
*
Diffstat (limited to 'js/games/nluqo.github.io/~bh/61a-pages/Lib/chapter3.code')
-rw-r--r-- | js/games/nluqo.github.io/~bh/61a-pages/Lib/chapter3.code | 1707 |
1 files changed, 1707 insertions, 0 deletions
diff --git a/js/games/nluqo.github.io/~bh/61a-pages/Lib/chapter3.code b/js/games/nluqo.github.io/~bh/61a-pages/Lib/chapter3.code new file mode 100644 index 0000000..656fff4 --- /dev/null +++ b/js/games/nluqo.github.io/~bh/61a-pages/Lib/chapter3.code @@ -0,0 +1,1707 @@ +;;;;CODE FROM CHAPTER 3 OF STRUCTURE AND INTERPRETATION OF COMPUTER PROGRAMS + +;;; Examples from the book are commented out with ;: so that they +;;; are easy to find and so that they will be omitted if you evaluate a +;;; chunk of the file (programs with intervening examples) in Scheme. + +;;; BEWARE: Although the whole file can be loaded into Scheme, +;;; you won't want to do so. For example, you generally do +;;; not want to use the procedural representation of pairs +;;; (cons, car, cdr as defined in section 3.3.1) instead of +;;; Scheme's primitive pairs. + +;;; Some things require code that is not in the book -- see ch3support.scm + + +;;;;SECTION 3.1 + +;;;SECTION 3.1.1 + +;: (withdraw 25) +;: (withdraw 25) +;: (withdraw 60) +;: (withdraw 15) + +(define balance 100) + +(define (withdraw amount) + (if (>= balance amount) + (begin (set! balance (- balance amount)) + balance) + "Insufficient funds")) + + +(define new-withdraw + (let ((balance 100)) + (lambda (amount) + (if (>= balance amount) + (begin (set! balance (- balance amount)) + balance) + "Insufficient funds")))) + + +(define (make-withdraw balance) + (lambda (amount) + (if (>= balance amount) + (begin (set! balance (- balance amount)) + balance) + "Insufficient funds"))) + + +;: (define W1 (make-withdraw 100)) +;: (define W2 (make-withdraw 100)) +;: (W1 50) +;: (W2 70) +;: (W2 40) +;: (W1 40) + + +(define (make-account balance) + (define (withdraw amount) + (if (>= balance amount) + (begin (set! balance (- balance amount)) + balance) + "Insufficient funds")) + (define (deposit amount) + (set! balance (+ balance amount)) + balance) + (define (dispatch m) + (cond ((eq? m 'withdraw) withdraw) + ((eq? m 'deposit) deposit) + (else (error "Unknown request -- MAKE-ACCOUNT" + m)))) + dispatch) + +;: (define acc (make-account 100)) + +;: ((acc 'withdraw) 50) +;: ((acc 'withdraw) 60) +;: ((acc 'deposit) 40) +;: ((acc 'withdraw) 60) + +;: (define acc2 (make-account 100)) + + +;; EXERCISE 3.1 +;: (define A (make-accumulator 5)) +;: (A 10) +;: (A 10) + + +;; EXERCISE 3.2 +;: (define s (make-monitored sqrt)) +;: (s 100) +;: (s 'how-many-calls?) + + +;; EXERCISE 3.3 +;: (define acc (make-account 100 'secret-password)) +;: ((acc 'secret-password 'withdraw) 40) +;: ((acc 'some-other-password 'deposit) 50) + + +;;;SECTION 3.1.2 + +;; *following uses rand-update -- see ch3support.scm +;; *also must set random-init to some value +(define random-init 7) ;**not in book** +(define rand + (let ((x random-init)) + (lambda () + (set! x (rand-update x)) + x))) + + +(define (estimate-pi trials) + (sqrt (/ 6 (monte-carlo trials cesaro-test)))) + +(define (cesaro-test) + (= (gcd (rand) (rand)) 1)) + +(define (monte-carlo trials experiment) + (define (iter trials-remaining trials-passed) + (cond ((= trials-remaining 0) + (/ trials-passed trials)) + ((experiment) + (iter (- trials-remaining 1) (+ trials-passed 1))) + (else + (iter (- trials-remaining 1) trials-passed)))) + (iter trials 0)) + +;; second version (no assignment) +(define (estimate-pi trials) + (sqrt (/ 6 (random-gcd-test trials random-init)))) + +(define (random-gcd-test trials initial-x) + (define (iter trials-remaining trials-passed x) + (let ((x1 (rand-update x))) + (let ((x2 (rand-update x1))) + (cond ((= trials-remaining 0) + (/ trials-passed trials)) + ((= (gcd x1 x2) 1) + (iter (- trials-remaining 1) + (+ trials-passed 1) + x2)) + (else + (iter (- trials-remaining 1) + trials-passed + x2)))))) + (iter trials 0 initial-x)) + + +;; EXERCISE 3.5 +(define (random-in-range low high) + (let ((range (- high low))) + (+ low (random range)))) + + +;;;SECTION 3.1.3 + +(define (make-simplified-withdraw balance) + (lambda (amount) + (set! balance (- balance amount)) + balance)) + + +;: (define W (make-simplified-withdraw 25)) +;: (W 20) +;: (W 10) + + +(define (make-decrementer balance) + (lambda (amount) + (- balance amount))) + +;: (define D (make-decrementer 25)) +;: (D 20) +;: (D 10) + +;: ((make-decrementer 25) 20) +;: ((lambda (amount) (- 25 amount)) 20) +;: (- 25 20) + +;: ((make-simplified-withdraw 25) 20) + +;: ((lambda (amount) (set! balance (- 25 amount)) 25) 20) +;: (set! balance (- 25 20)) 25 + +;;;Sameness and change + +;: (define D1 (make-decrementer 25)) +;: (define D2 (make-decrementer 25)) +;: +;: (define W1 (make-simplified-withdraw 25)) +;: (define W2 (make-simplified-withdraw 25)) +;: +;: (W1 20) +;: (W1 20) +;: (W2 20) + +;: (define peter-acc (make-account 100)) +;: (define paul-acc (make-account 100)) +;: +;: (define peter-acc (make-account 100)) +;: (define paul-acc peter-acc) + +;;;Pitfalls of imperative programming + +(define (factorial n) + (define (iter product counter) + (if (> counter n) + product + (iter (* counter product) + (+ counter 1)))) + (iter 1 1)) + +(define (factorial n) + (let ((product 1) + (counter 1)) + (define (iter) + (if (> counter n) + product + (begin (set! product (* counter product)) + (set! counter (+ counter 1)) + (iter)))) + (iter))) + + +;; EXERCISE 3.7 +;: (define paul-acc +;: (make-joint peter-acc 'open-sesame 'rosebud)) + + +;;;;SECTION 3.2 + +;;;SECTION 3.2.1 + +(define (square x) + (* x x)) + +(define square + (lambda (x) (* x x))) + + +;;;SECTION 3.2.2 + +(define (square x) + (* x x)) + +(define (sum-of-squares x y) + (+ (square x) (square y))) + +(define (f a) + (sum-of-squares (+ a 1) (* a 2))) + +;: (sum-of-squares (+ a 1) (* a 2)) + + +;; EXERCISE 3.9 + +(define (factorial n) + (if (= n 1) + 1 + (* n (factorial (- n 1))))) + +(define (factorial n) + (fact-iter 1 1 n)) + +(define (fact-iter product counter max-count) + (if (> counter max-count) + product + (fact-iter (* counter product) + (+ counter 1) + max-count))) + + +;;;SECTION 3.2.3 + +(define (make-withdraw balance) + (lambda (amount) + (if (>= balance amount) + (begin (set! balance (- balance amount)) + balance) + "Insufficient funds"))) + +;: (define W1 (make-withdraw 100)) +;: (W1 50) + +;: (define W2 (make-withdraw 100)) + + +;; EXERCISE 3.10 + +(define (make-withdraw initial-amount) + (let ((balance initial-amount)) + (lambda (amount) + (if (>= balance amount) + (begin (set! balance (- balance amount)) + balance) + "Insufficient funds")))) + + +;: (define W1 (make-withdraw 100)) +;: (W1 50) +;: (define W2 (make-withdraw 100)) + + +;;;SECTION 3.2.4 + +;; same as in section 1.1.8 +(define (sqrt x) + (define (good-enough? guess) + (< (abs (- (square guess) x)) 0.001)) + (define (improve guess) + (average guess (/ x guess))) + (define (sqrt-iter guess) + (if (good-enough? guess) + guess + (sqrt-iter (improve guess)))) + (sqrt-iter 1.0)) + + +;; EXERCISE 3.11 + +(define (make-account balance) + (define (withdraw amount) + (if (>= balance amount) + (begin (set! balance (- balance amount)) + balance) + "Insufficient funds")) + (define (deposit amount) + (set! balance (+ balance amount)) + balance) + (define (dispatch m) + (cond ((eq? m 'withdraw) withdraw) + ((eq? m 'deposit) deposit) + (else (error "Unknown request -- MAKE-ACCOUNT" + m)))) + dispatch) + +;: (define acc (make-account 50)) +;: +;: ((acc 'deposit) 40) +;: ((acc 'withdraw) 60) +;: +;: (define acc2 (make-account 100)) + + +;;;;SECTION 3.3 + +;;;SECTION 3.3.1 + +(define (cons x y) + (let ((new (get-new-pair))) + (set-car! new x) + (set-cdr! new y) + new)) + + +;; EXERCISE 3.12 +(define (append x y) + (if (null? x) + y + (cons (car x) (append (cdr x) y)))) + +(define (append! x y) + (set-cdr! (last-pair x) y) + x) + +(define (last-pair x) + (if (null? (cdr x)) + x + (last-pair (cdr x)))) + +;: (define x (list 'a 'b)) +;: (define y (list 'c 'd)) +;: (define z (append x y)) +;: z +;: (cdr x) +;: +;: (define w (append! x y)) +;: w +;: (cdr x) + + +;; EXERCISE 3.13 +(define (make-cycle x) + (set-cdr! (last-pair x) x) + x) + +;: (define z (make-cycle (list 'a 'b 'c))) + + +;; EXERCISE 3.14 +(define (mystery x) + (define (loop x y) + (if (null? x) + y + (let ((temp (cdr x))) + (set-cdr! x y) + (loop temp x)))) + (loop x '())) + + +;;; Sharing and identity + +;: (define x (list 'a 'b)) +;: (define z1 (cons x x)) +;: (define z2 (cons (list 'a 'b) (list 'a 'b))) + +(define (set-to-wow! x) + (set-car! (car x) 'wow) + x) + +;: z1 +;: (set-to-wow! z1) +;: z2 +;: (set-to-wow! z2) + + +;; EXERCISE 3.16 +(define (count-pairs x) + (if (not (pair? x)) + 0 + (+ (count-pairs (car x)) + (count-pairs (cdr x)) + 1))) + + +;;;Mutation as assignment + +(define (cons x y) + (define (dispatch m) + (cond ((eq? m 'car) x) + ((eq? m 'cdr) y) + (else (error "Undefined operation -- CONS" m)))) + dispatch) + +(define (car z) (z 'car)) +(define (cdr z) (z 'cdr)) + + +(define (cons x y) + (define (set-x! v) (set! x v)) + (define (set-y! v) (set! y v)) + (define (dispatch m) + (cond ((eq? m 'car) x) + ((eq? m 'cdr) y) + ((eq? m 'set-car!) set-x!) + ((eq? m 'set-cdr!) set-y!) + (else (error "Undefined operation -- CONS" m)))) + dispatch) + +(define (car z) (z 'car)) +(define (cdr z) (z 'cdr)) + +(define (set-car! z new-value) + ((z 'set-car!) new-value) + z) + +(define (set-cdr! z new-value) + ((z 'set-cdr!) new-value) + z) + + +;; EXERCISE 3.20 +;: (define x (cons 1 2)) +;: (define z (cons x x)) +;: (set-car! (cdr z) 17) +;: (car x) + + +;;;SECTION 3.3.2 + +(define (front-ptr queue) (car queue)) +(define (rear-ptr queue) (cdr queue)) +(define (set-front-ptr! queue item) (set-car! queue item)) +(define (set-rear-ptr! queue item) (set-cdr! queue item)) + +(define (empty-queue? queue) (null? (front-ptr queue))) +(define (make-queue) (cons '() '())) + +(define (front-queue queue) + (if (empty-queue? queue) + (error "FRONT called with an empty queue" queue) + (car (front-ptr queue)))) + +(define (insert-queue! queue item) + (let ((new-pair (cons item '()))) + (cond ((empty-queue? queue) + (set-front-ptr! queue new-pair) + (set-rear-ptr! queue new-pair) + queue) + (else + (set-cdr! (rear-ptr queue) new-pair) + (set-rear-ptr! queue new-pair) + queue)))) + +(define (delete-queue! queue) + (cond ((empty-queue? queue) + (error "DELETE! called with an empty queue" queue)) + (else + (set-front-ptr! queue (cdr (front-ptr queue))) + queue))) + + +;; EXERCISE 3.21 +;: (define q1 (make-queue)) +;: (insert-queue! q1 'a) +;: (insert-queue! q1 'b) +;: (delete-queue! q1) +;: (delete-queue! q1) + + +;;;SECTION 3.3.3 + +(define (lookup key table) + (let ((record (assoc key (cdr table)))) + (if record + (cdr record) + false))) + +(define (assoc key records) + (cond ((null? records) false) + ((equal? key (caar records)) (car records)) + (else (assoc key (cdr records))))) + +(define (insert! key value table) + (let ((record (assoc key (cdr table)))) + (if record + (set-cdr! record value) + (set-cdr! table + (cons (cons key value) (cdr table))))) + 'ok) + +(define (make-table) + (list '*table*)) + +;; two-dimensional +(define (lookup key-1 key-2 table) + (let ((subtable (assoc key-1 (cdr table)))) + (if subtable + (let ((record (assoc key-2 (cdr subtable)))) + (if record + (cdr record) + false)) + false))) + +(define (insert! key-1 key-2 value table) + (let ((subtable (assoc key-1 (cdr table)))) + (if subtable + (let ((record (assoc key-2 (cdr subtable)))) + (if record + (set-cdr! record value) + (set-cdr! subtable + (cons (cons key-2 value) + (cdr subtable))))) + (set-cdr! table + (cons (list key-1 + (cons key-2 value)) + (cdr table))))) + 'ok) + +;; local tables +(define (make-table) + (let ((local-table (list '*table*))) + (define (lookup key-1 key-2) + (let ((subtable (assoc key-1 (cdr local-table)))) + (if subtable + (let ((record (assoc key-2 (cdr subtable)))) + (if record + (cdr record) + false)) + false))) + (define (insert! key-1 key-2 value) + (let ((subtable (assoc key-1 (cdr local-table)))) + (if subtable + (let ((record (assoc key-2 (cdr subtable)))) + (if record + (set-cdr! record value) + (set-cdr! subtable + (cons (cons key-2 value) + (cdr subtable))))) + (set-cdr! local-table + (cons (list key-1 + (cons key-2 value)) + (cdr local-table))))) + 'ok) + (define (dispatch m) + (cond ((eq? m 'lookup-proc) lookup) + ((eq? m 'insert-proc!) insert!) + (else (error "Unknown operation -- TABLE" m)))) + dispatch)) + +(define operation-table (make-table)) +(define get (operation-table 'lookup-proc)) +(define put (operation-table 'insert-proc!)) + + +;; EXERCISE 3.27 +(define (fib n) + (cond ((= n 0) 0) + ((= n 1) 1) + (else (+ (fib (- n 1)) + (fib (- n 2)))))) + +(define (memoize f) + (let ((table (make-table))) + (lambda (x) + (let ((previously-computed-result (lookup x table))) + (or previously-computed-result + (let ((result (f x))) + (insert! x result table) + result)))))) + +(define memo-fib + (memoize (lambda (n) + (cond ((= n 0) 0) + ((= n 1) 1) + (else (+ (memo-fib (- n 1)) + (memo-fib (- n 2)))))))) + +;;;SECTION 3.3.4 + +;: (define a (make-wire)) +;: (define b (make-wire)) +;: (define c (make-wire)) +;: (define d (make-wire)) +;: (define e (make-wire)) +;: (define s (make-wire)) +;: +;: (or-gate a b d) +;: (and-gate a b c) +;: (inverter c e) +;: (and-gate d e s) + + +;;NB. To use half-adder, need or-gate from exercise 3.28 +(define (half-adder a b s c) + (let ((d (make-wire)) (e (make-wire))) + (or-gate a b d) + (and-gate a b c) + (inverter c e) + (and-gate d e s) + 'ok)) + +(define (full-adder a b c-in sum c-out) + (let ((s (make-wire)) + (c1 (make-wire)) + (c2 (make-wire))) + (half-adder b c-in s c1) + (half-adder a s sum c2) + (or-gate c1 c2 c-out) + 'ok)) + +(define (inverter input output) + (define (invert-input) + (let ((new-value (logical-not (get-signal input)))) + (after-delay inverter-delay + (lambda () + (set-signal! output new-value))))) + (add-action! input invert-input) + 'ok) + +(define (logical-not s) + (cond ((= s 0) 1) + ((= s 1) 0) + (else (error "Invalid signal" s)))) + +;; *following uses logical-and -- see ch3support.scm + +(define (and-gate a1 a2 output) + (define (and-action-procedure) + (let ((new-value + (logical-and (get-signal a1) (get-signal a2)))) + (after-delay and-gate-delay + (lambda () + (set-signal! output new-value))))) + (add-action! a1 and-action-procedure) + (add-action! a2 and-action-procedure) + 'ok) + + +(define (make-wire) + (let ((signal-value 0) (action-procedures '())) + (define (set-my-signal! new-value) + (if (not (= signal-value new-value)) + (begin (set! signal-value new-value) + (call-each action-procedures)) + 'done)) + (define (accept-action-procedure! proc) + (set! action-procedures (cons proc action-procedures)) + (proc)) + (define (dispatch m) + (cond ((eq? m 'get-signal) signal-value) + ((eq? m 'set-signal!) set-my-signal!) + ((eq? m 'add-action!) accept-action-procedure!) + (else (error "Unknown operation -- WIRE" m)))) + dispatch)) + +(define (call-each procedures) + (if (null? procedures) + 'done + (begin + ((car procedures)) + (call-each (cdr procedures))))) + +(define (get-signal wire) + (wire 'get-signal)) + +(define (set-signal! wire new-value) + ((wire 'set-signal!) new-value)) + +(define (add-action! wire action-procedure) + ((wire 'add-action!) action-procedure)) + +(define (after-delay delay action) + (add-to-agenda! (+ delay (current-time the-agenda)) + action + the-agenda)) + +(define (propagate) + (if (empty-agenda? the-agenda) + 'done + (let ((first-item (first-agenda-item the-agenda))) + (first-item) + (remove-first-agenda-item! the-agenda) + (propagate)))) + +(define (probe name wire) + (add-action! wire + (lambda () + (newline) + (display name) + (display " ") + (display (current-time the-agenda)) + (display " New-value = ") + (display (get-signal wire))))) + +;;; Sample simulation + +;: (define the-agenda (make-agenda)) +;: (define inverter-delay 2) +;: (define and-gate-delay 3) +;: (define or-gate-delay 5) +;: +;: (define input-1 (make-wire)) +;: (define input-2 (make-wire)) +;: (define sum (make-wire)) +;: (define carry (make-wire)) +;: +;: (probe 'sum sum) +;: (probe 'carry carry) +;: +;: (half-adder input-1 input-2 sum carry) +;: (set-signal! input-1 1) +;: (propagate) +;: +;: (set-signal! input-2 1) +;: (propagate) + + +;; EXERCISE 3.31 +;: (define (accept-action-procedure! proc) +;: (set! action-procedures (cons proc action-procedures))) + + +;;;Implementing agenda + +(define (make-time-segment time queue) + (cons time queue)) +(define (segment-time s) (car s)) +(define (segment-queue s) (cdr s)) + +(define (make-agenda) (list 0)) + +(define (current-time agenda) (car agenda)) +(define (set-current-time! agenda time) + (set-car! agenda time)) + +(define (segments agenda) (cdr agenda)) +(define (set-segments! agenda segments) + (set-cdr! agenda segments)) +(define (first-segment agenda) (car (segments agenda))) +(define (rest-segments agenda) (cdr (segments agenda))) + +(define (empty-agenda? agenda) + (null? (segments agenda))) + +(define (add-to-agenda! time action agenda) + (define (belongs-before? segments) + (or (null? segments) + (< time (segment-time (car segments))))) + (define (make-new-time-segment time action) + (let ((q (make-queue))) + (insert-queue! q action) + (make-time-segment time q))) + (define (add-to-segments! segments) + (if (= (segment-time (car segments)) time) + (insert-queue! (segment-queue (car segments)) + action) + (let ((rest (cdr segments))) + (if (belongs-before? rest) + (set-cdr! + segments + (cons (make-new-time-segment time action) + (cdr segments))) + (add-to-segments! rest))))) + (let ((segments (segments agenda))) + (if (belongs-before? segments) + (set-segments! + agenda + (cons (make-new-time-segment time action) + segments)) + (add-to-segments! segments)))) + +(define (remove-first-agenda-item! agenda) + (let ((q (segment-queue (first-segment agenda)))) + (delete-queue! q) + (if (empty-queue? q) + (set-segments! agenda (rest-segments agenda))))) + +(define (first-agenda-item agenda) + (if (empty-agenda? agenda) + (error "Agenda is empty -- FIRST-AGENDA-ITEM") + (let ((first-seg (first-segment agenda))) + (set-current-time! agenda (segment-time first-seg)) + (front-queue (segment-queue first-seg))))) + + +;;;SECTION 3.3.5 + +;: (define C (make-connector)) +;: (define F (make-connector)) +;: (celsius-fahrenheit-converter C F) + +(define (celsius-fahrenheit-converter c f) + (let ((u (make-connector)) + (v (make-connector)) + (w (make-connector)) + (x (make-connector)) + (y (make-connector))) + (multiplier c w u) + (multiplier v x u) + (adder v y f) + (constant 9 w) + (constant 5 x) + (constant 32 y) + 'ok)) + +;: (probe "Celsius temp" C) +;: (probe "Fahrenheit temp" F) +;: (set-value! C 25 'user) +;: (set-value! F 212 'user) +;: (forget-value! C 'user) +;: (set-value! F 212 'user) + + +(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) + (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 (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 (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)) + + +;; EXERCISE 3.34 + +(define (squarer a b) + (multiplier a a b)) + + + +;; EXERCISE 3.36 +;: (define a (make-connector)) +;: (define b (make-connector)) +;: (set-value! a 10 'user) + + +;; EXERCISE 3.37 + +(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+ x y) + (let ((z (make-connector))) + (adder x y z) + z)) + + +;;;SECTION 3.4 +;;;**Need parallel-execute, available for MIT Scheme + +;;;SECTION 3.4.1 + +(define (withdraw amount) + (if (>= balance amount) + (begin (set! balance (- balance amount)) + balance) + "Insufficient funds")) + + +;; EXERCISE 3.38 +;: (set! balance (+ balance 10)) +;: (set! balance (- balance 20)) +;: (set! balance (- balance (/ balance 2))) + + +;;;SECTION 3.4.2 + +;: (define x 10) +;: (parallel-execute (lambda () (set! x (* x x))) +;: (lambda () (set! x (+ x 1)))) + +;: (define x 10) +;: (define s (make-serializer)) +;: (parallel-execute (s (lambda () (set! x (* x x)))) +;: (s (lambda () (set! x (+ x 1))))) + + +(define (make-account balance) + (define (withdraw amount) + (if (>= balance amount) + (begin (set! balance (- balance amount)) + balance) + "Insufficient funds")) + (define (deposit amount) + (set! balance (+ balance amount)) + balance) + (let ((protected (make-serializer))) + (define (dispatch m) + (cond ((eq? m 'withdraw) (protected withdraw)) + ((eq? m 'deposit) (protected deposit)) + ((eq? m 'balance) balance) + (else (error "Unknown request -- MAKE-ACCOUNT" + m)))) + dispatch)) + + +;; EXERCISE 3.39 + +;: (define x 10) +;: (define s (make-serializer)) +;: (parallel-execute (lambda () (set! x ((s (lambda () (* x x)))))) +;: (s (lambda () (set! x (+ x 1))))) + + +;; EXERCISE 3.40 + +;: (define x 10) +;: (parallel-execute (lambda () (set! x (* x x))) +;: (lambda () (set! x (* x x x)))) +;: +;: +;: (define x 10) +;: (define s (make-serializer)) +;: (parallel-execute (s (lambda () (set! x (* x x)))) +;: (s (lambda () (set! x (* x x x))))) + + +;; EXERCISE 3.41 + +(define (make-account balance) + (define (withdraw amount) + (if (>= balance amount) + (begin (set! balance (- balance amount)) + balance) + "Insufficient funds")) + (define (deposit amount) + (set! balance (+ balance amount)) + balance) + (let ((protected (make-serializer))) + (define (dispatch m) + (cond ((eq? m 'withdraw) (protected withdraw)) + ((eq? m 'deposit) (protected deposit)) + ((eq? m 'balance) + ((protected (lambda () balance)))) + (else (error "Unknown request -- MAKE-ACCOUNT" + m)))) + dispatch)) + +;; EXERCISE 3.42 + +(define (make-account balance) + (define (withdraw amount) + (if (>= balance amount) + (begin (set! balance (- balance amount)) + balance) + "Insufficient funds")) + (define (deposit amount) + (set! balance (+ balance amount)) + balance) + (let ((protected (make-serializer))) + (let ((protected-withdraw (protected withdraw)) + (protected-deposit (protected deposit))) + (define (dispatch m) + (cond ((eq? m 'withdraw) protected-withdraw) + ((eq? m 'deposit) protected-deposit) + ((eq? m 'balance) balance) + (else (error "Unknown request -- MAKE-ACCOUNT" + m)))) + dispatch))) + +;;;Multiple shared resources + +(define (exchange account1 account2) + (let ((difference (- (account1 'balance) + (account2 'balance)))) + ((account1 'withdraw) difference) + ((account2 'deposit) difference))) + +(define (make-account-and-serializer balance) + (define (withdraw amount) + (if (>= balance amount) + (begin (set! balance (- balance amount)) + balance) + "Insufficient funds")) + (define (deposit amount) + (set! balance (+ balance amount)) + balance) + (let ((balance-serializer (make-serializer))) + (define (dispatch m) + (cond ((eq? m 'withdraw) withdraw) + ((eq? m 'deposit) deposit) + ((eq? m 'balance) balance) + ((eq? m 'serializer) balance-serializer) + (else (error "Unknown request -- MAKE-ACCOUNT" + m)))) + dispatch)) + + +(define (deposit account amount) + (let ((s (account 'serializer)) + (d (account 'deposit))) + ((s d) amount))) + +(define (serialized-exchange account1 account2) + (let ((serializer1 (account1 'serializer)) + (serializer2 (account2 'serializer))) + ((serializer1 (serializer2 exchange)) + account1 + account2))) + + +;; EXERCISE 3.44 + +(define (transfer from-account to-account amount) + ((from-account 'withdraw) amount) + ((to-account 'deposit) amount)) + + +;; EXERCISE 3.45 + +(define (make-account-and-serializer balance) + (define (withdraw amount) + (if (>= balance amount) + (begin (set! balance (- balance amount)) + balance) + "Insufficient funds")) + (define (deposit amount) + (set! balance (+ balance amount)) + balance) + (let ((balance-serializer (make-serializer))) + (define (dispatch m) + (cond ((eq? m 'withdraw) (balance-serializer withdraw)) + ((eq? m 'deposit) (balance-serializer deposit)) + ((eq? m 'balance) balance) + ((eq? m 'serializer) balance-serializer) + (else (error "Unknown request -- MAKE-ACCOUNT" + m)))) + dispatch)) + +(define (deposit account amount) + ((account 'deposit) amount)) + + +;;;Implementing serializers + +(define (make-serializer) + (let ((mutex (make-mutex))) + (lambda (p) + (define (serialized-p . args) + (mutex 'acquire) + (let ((val (apply p args))) + (mutex 'release) + val)) + serialized-p))) + +(define (make-mutex) + (let ((cell (list false))) + (define (the-mutex m) + (cond ((eq? m 'acquire) + (if (test-and-set! cell) + (the-mutex 'acquire))) + ((eq? m 'release) (clear! cell)))) + the-mutex)) + +(define (clear! cell) + (set-car! cell false)) + +(define (test-and-set! cell) + (if (car cell) + true + (begin (set-car! cell true) + false))) + +;;from footnote -- MIT Scheme +(define (test-and-set! cell) + (without-interrupts + (lambda () + (if (car cell) + true + (begin (set-car! cell true) + false))))) + +;;;SECTION 3.5 + +;;;SECTION 3.5.1 + +(define (sum-primes a b) + (define (iter count accum) + (cond ((> count b) accum) + ((prime? count) (iter (+ count 1) (+ count accum))) + (else (iter (+ count 1) accum)))) + (iter a 0)) + + +(define (sum-primes a b) + (accumulate + + 0 + (filter prime? (enumerate-interval a b)))) + +;: (car (cdr (filter prime? +;: (enumerate-interval 10000 1000000)))) + +(define (stream-ref s n) + (if (= n 0) + (stream-car s) + (stream-ref (stream-cdr s) (- n 1)))) + +(define (stream-map proc s) + (if (stream-null? s) + the-empty-stream + (cons-stream (proc (stream-car s)) + (stream-map proc (stream-cdr s))))) + +(define (stream-for-each proc s) + (if (stream-null? s) + 'done + (begin (proc (stream-car s)) + (stream-for-each proc (stream-cdr s))))) + +(define (display-stream s) + (stream-for-each display-line s)) + +(define (display-line x) + (newline) + (display x)) + + + +;; stream-car and stream-cdr would normally be built into +;; the stream implementation +;: (define (stream-car stream) (car stream)) +;: (define (stream-cdr stream) (force (cdr stream))) + +;: (stream-car +;: (stream-cdr +;: (stream-filter prime? +;: (stream-enumerate-interval 10000 1000000)))) + +(define (stream-enumerate-interval low high) + (if (> low high) + the-empty-stream + (cons-stream + low + (stream-enumerate-interval (+ low 1) high)))) + +(define (stream-filter pred stream) + (cond ((stream-null? stream) the-empty-stream) + ((pred (stream-car stream)) + (cons-stream (stream-car stream) + (stream-filter pred + (stream-cdr stream)))) + (else (stream-filter pred (stream-cdr stream))))) + + +;; force would normally be built into +;; the stream implementation +;: (define (force delayed-object) +;: (delayed-object)) + +(define (memo-proc proc) + (let ((already-run? false) (result false)) + (lambda () + (if (not already-run?) + (begin (set! result (proc)) + (set! already-run? true) + result) + result)))) + + +;; EXERCISE 3.51 + +(define (show x) + (display-line x) + x) + +;: (define x (stream-map show (stream-enumerate-interval 0 10))) +;: (stream-ref x 5) +;: (stream-ref x 7) + + +;; EXERCISE 3.52 + +(define sum 0) + +(define (accum x) + (set! sum (+ x sum)) + sum) + +;: (define seq (stream-map accum (stream-enumerate-interval 1 20))) +;: (define y (stream-filter even? seq)) +;: (define z (stream-filter (lambda (x) (= (remainder x 5) 0)) +;: seq)) + +;: (stream-ref y 7) +;: (display-stream z) + + +;;;SECTION 3.5.2 + +(define (integers-starting-from n) + (cons-stream n (integers-starting-from (+ n 1)))) + +(define integers (integers-starting-from 1)) + +(define (divisible? x y) (= (remainder x y) 0)) + +(define no-sevens + (stream-filter (lambda (x) (not (divisible? x 7))) + integers)) + +;: (stream-ref no-sevens 100) + +(define (fibgen a b) + (cons-stream a (fibgen b (+ a b)))) + +(define fibs (fibgen 0 1)) + +(define (sieve stream) + (cons-stream + (stream-car stream) + (sieve (stream-filter + (lambda (x) + (not (divisible? x (stream-car stream)))) + (stream-cdr stream))))) + +(define primes (sieve (integers-starting-from 2))) + +;: (stream-ref primes 50) + + +;;;Defining streams implicitly;;;Defining streams implicitly + +(define ones (cons-stream 1 ones)) + +(define (add-streams s1 s2) + (stream-map + s1 s2)) + +(define integers (cons-stream 1 (add-streams ones integers))) + +(define fibs + (cons-stream 0 + (cons-stream 1 + (add-streams (stream-cdr fibs) + fibs)))) + +(define (scale-stream stream factor) + (stream-map (lambda (x) (* x factor)) stream)) + +(define double (cons-stream 1 (scale-stream double 2))) + +(define primes + (cons-stream + 2 + (stream-filter prime? (integers-starting-from 3)))) + +(define (prime? n) + (define (iter ps) + (cond ((> (square (stream-car ps)) n) true) + ((divisible? n (stream-car ps)) false) + (else (iter (stream-cdr ps))))) + (iter primes)) + + +;; EXERCISE 3.53 +;: (define s (cons-stream 1 (add-streams s s))) + + +;; EXERCISE 3.56 +(define (merge s1 s2) + (cond ((stream-null? s1) s2) + ((stream-null? s2) s1) + (else + (let ((s1car (stream-car s1)) + (s2car (stream-car s2))) + (cond ((< s1car s2car) + (cons-stream s1car (merge (stream-cdr s1) s2))) + ((> s1car s2car) + (cons-stream s2car (merge s1 (stream-cdr s2)))) + (else + (cons-stream s1car + (merge (stream-cdr s1) + (stream-cdr s2))))))))) + + +;; EXERCISE 3.58 +(define (expand num den radix) + (cons-stream + (quotient (* num radix) den) + (expand (remainder (* num radix) den) den radix))) + + +;; EXERCISE 3.59 +;: (define exp-series +;: (cons-stream 1 (integrate-series exp-series))) + + +;;;SECTION 3.5.3 + +(define (sqrt-improve guess x) + (average guess (/ x guess))) + + +(define (sqrt-stream x) + (define guesses + (cons-stream 1.0 + (stream-map (lambda (guess) + (sqrt-improve guess x)) + guesses))) + guesses) + +;: (display-stream (sqrt-stream 2)) + + +(define (pi-summands n) + (cons-stream (/ 1.0 n) + (stream-map - (pi-summands (+ n 2))))) + +;: (define pi-stream +;: (scale-stream (partial-sums (pi-summands 1)) 4)) + +;: (display-stream pi-stream) + + +(define (euler-transform s) + (let ((s0 (stream-ref s 0)) + (s1 (stream-ref s 1)) + (s2 (stream-ref s 2))) + (cons-stream (- s2 (/ (square (- s2 s1)) + (+ s0 (* -2 s1) s2))) + (euler-transform (stream-cdr s))))) + +;: (display-stream (euler-transform pi-stream)) + + +(define (make-tableau transform s) + (cons-stream s + (make-tableau transform + (transform s)))) + +(define (accelerated-sequence transform s) + (stream-map stream-car + (make-tableau transform s))) + +;: (display-stream (accelerated-sequence euler-transform +;: pi-stream)) + + +;; EXERCISE 3.63 +(define (sqrt-stream x) + (cons-stream 1.0 + (stream-map (lambda (guess) + (sqrt-improve guess x)) + (sqrt-stream x)))) + +;; EXERCISE 3.64 +(define (sqrt x tolerance) + (stream-limit (sqrt-stream x) tolerance)) + + +;;; Infinite streams of pairs + +;: (stream-filter (lambda (pair) +;: (prime? (+ (car pair) (cadr pair)))) +;: int-pairs) + +(define (stream-append s1 s2) + (if (stream-null? s1) + s2 + (cons-stream (stream-car s1) + (stream-append (stream-cdr s1) s2)))) + + +;: (pairs integers integers) + + +(define (interleave s1 s2) + (if (stream-null? s1) + s2 + (cons-stream (stream-car s1) + (interleave s2 (stream-cdr s1))))) + +(define (pairs s t) + (cons-stream + (list (stream-car s) (stream-car t)) + (interleave + (stream-map (lambda (x) (list (stream-car s) x)) + (stream-cdr t)) + (pairs (stream-cdr s) (stream-cdr t))))) + + +;; EXERCISE 3.68 + +(define (pairs s t) + (interleave + (stream-map (lambda (x) (list (stream-car s) x)) + t) + (pairs (stream-cdr s) (stream-cdr t)))) + + +;;; Streams as signals + +(define (integral integrand initial-value dt) + (define int + (cons-stream initial-value + (add-streams (scale-stream integrand dt) + int))) + int) + + +;; EXERCISE 3.74 + +(define (make-zero-crossings input-stream last-value) + (cons-stream + (sign-change-detector (stream-car input-stream) last-value) + (make-zero-crossings (stream-cdr input-stream) + (stream-car input-stream)))) + +;: (define zero-crossings (make-zero-crossings sense-data 0)) + + + +;; EXERCISE 3.75 + +(define (make-zero-crossings input-stream last-value) + (let ((avpt (/ (+ (stream-car input-stream) last-value) 2))) + (cons-stream (sign-change-detector avpt last-value) + (make-zero-crossings (stream-cdr input-stream) + avpt)))) + + +;;;SECTION 3.5.4 + +(define (solve f y0 dt) + (define y (integral dy y0 dt)) + (define dy (stream-map f y)) + y) + +(define (integral delayed-integrand initial-value dt) + (define int + (cons-stream initial-value + (let ((integrand (force delayed-integrand))) + (add-streams (scale-stream integrand dt) + int)))) + int) + +(define (solve f y0 dt) + (define y (integral (delay dy) y0 dt)) + (define dy (stream-map f y)) + y) + + +;: (stream-ref (solve (lambda (y) y) 1 0.001) 1000) + + +;; EXERCISE 3.77 + +(define (integral integrand initial-value dt) + (cons-stream initial-value + (if (stream-null? integrand) + the-empty-stream + (integral (stream-cdr integrand) + (+ (* dt (stream-car integrand)) + initial-value) + dt)))) + +;;;SECTION 3.5.5 + +;; same as in section 3.1.2 +(define rand + (let ((x random-init)) + (lambda () + (set! x (rand-update x)) + x))) + + +(define random-numbers + (cons-stream random-init + (stream-map rand-update random-numbers))) + + +;: (define cesaro-stream +;: (map-successive-pairs (lambda (r1 r2) (= (gcd r1 r2) 1)) +;: random-numbers)) + +(define (map-successive-pairs f s) + (cons-stream + (f (stream-car s) (stream-car (stream-cdr s))) + (map-successive-pairs f (stream-cdr (stream-cdr s))))) + + +(define (monte-carlo experiment-stream passed failed) + (define (next passed failed) + (cons-stream + (/ passed (+ passed failed)) + (monte-carlo + (stream-cdr experiment-stream) passed failed))) + (if (stream-car experiment-stream) + (next (+ passed 1) failed) + (next passed (+ failed 1)))) + +;: (define pi +;: (stream-map (lambda (p) (sqrt (/ 6 p))) +;: (monte-carlo cesaro-stream 0 0))) + + +;; same as in section 3.1.3 +(define (make-simplified-withdraw balance) + (lambda (amount) + (set! balance (- balance amount)) + balance)) + +(define (stream-withdraw balance amount-stream) + (cons-stream + balance + (stream-withdraw (- balance (stream-car amount-stream)) + (stream-cdr amount-stream)))) + + |