;;;;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))))