#lang racket ;;;;;;;;; ;; 3.1 ;; ;;;;;;;;; (define (make-accumulator total) (lambda (amount) (set! total (+ total amount)) total)) ;; tests (define A (make-accumulator 5)) (A 10) ;; 15 (A 10) ;; 25 ;;;;;;;;; ;; 3.2 ;; ;;;;;;;;; (define (make-monitored f) (define num-calls 0) (lambda (input) (cond [(equal? input 'how-many-calls?) num-calls] [(equal? input 'reset-num-calls) (set! num-calls 0)] [else (set! num-calls (add1 num-calls)) (f input)]))) ;; tests (define s (make-monitored sqrt)) (s 100) ;; 10 (s 81) ;; 9 (s 64) ;; 8 (s 'how-many-calls?) ;; 3 (s 'reset-num-calls) (s 'how-many-calls?) ;; 0 ;;;;;;;;; ;; 3.3 ;; ;;;;;;;;; (define (display-error message) (lambda (amount) message)) (define (make-account balance password) (define (withdraw amount) (cond [(>= balance amount) (set! balance (- balance amount)) balance] [else "Insufficient funds"])) (define (deposit amount) (set! balance (+ balance amount)) balance) (define (dispatch pw m) (if (eq? pw password) (cond [(eq? m 'withdraw) withdraw] [(eq? m 'deposit) deposit] [else (display-error "Unknown request -- MAKE-ACCOUNT")]) (display-error "Incorrect password"))) dispatch) ;; tests (define acc (make-account 100 'abc)) ((acc 'abc 'deposit) 100) ;; 200 ((acc 'abc 'withdraw) 50) ;; 150 ((acc 'abc 'withdraw) 200) ;; "Insufficient funds" ((acc 'xyz 'withdraw) 1000000) ;; "Incorrect password" ((acc 'abc 'invest) 1000) ;; "Unknown request -- MAKE-ACCOUNT" ((acc 'abc 'deposit) 25) ;; 175 ;;;;;;;;; ;; 3.4 ;; ;;;;;;;;; (define (make-secure-account balance password) (define number-wrong-guesses 0) (define (call-the-cops) (display-error "The police have been called")) (define (withdraw amount) (cond [(>= balance amount) (set! balance (- balance amount)) balance] [else "Insufficient funds"])) (define (deposit amount) (set! balance (+ balance amount)) balance) (define (dispatch pw m) (cond [(eq? pw password) (set! number-wrong-guesses 0) (cond [(eq? m 'withdraw) withdraw] [(eq? m 'deposit) deposit] [else (display-error "Unknown request -- MAKE-ACCOUNT")])] [(< number-wrong-guesses 7) (set! number-wrong-guesses (add1 number-wrong-guesses)) (display-error "Incorrect password")] [else (call-the-cops)])) dispatch) ;; tests (define new-acc (make-secure-account 100 'abc)) ((new-acc 'abc 'deposit) 50) ;; 150 ((new-acc 'xyz1 'withdraw) 1000000) ;; "Incorrect password" ((new-acc 'xyz2 'withdraw) 1000000) ;; "Incorrect password" ((new-acc 'xyz3 'withdraw) 1000000) ;; "Incorrect password" ((new-acc 'xyz4 'withdraw) 1000000) ;; "Incorrect password" ((new-acc 'xyz5 'withdraw) 1000000) ;; "Incorrect password" ((new-acc 'xyz6 'withdraw) 1000000) ;; "Incorrect password" ((new-acc 'xyz7 'withdraw) 1000000) ;; "Incorrect password" ((new-acc 'xyz8 'withdraw) 1000000) ;; "The police have been called" ;;;;;;;;; ;; 3.5 ;; ;;;;;;;;; (define (inexact-random low high) ; Return a random inexact real in the interval (low, high). (+ low (* (random) (- high low)))) (define (monte-carlo trials experiment) (define (iter trials-remaining trials-passed) ;; (printf "~a ~a ~n" trials-remaining trials-passed) (cond [(zero? trials-remaining) (exact->inexact (/ trials-passed trials))] [else (define hit (experiment)) (if hit (iter (sub1 trials-remaining) (add1 trials-passed)) (iter (sub1 trials-remaining) trials-passed))])) (iter trials 0)) (define (estimate-integral predicate x1 x2 y1 y2 num-trials) (define total-area (* (- x2 x1) (- y2 y1))) (define (integral-experiment) (define x (inexact-random x1 x2)) (define y (inexact-random y1 y2)) (predicate x y)) (* (monte-carlo num-trials integral-experiment) total-area)) (define (estimate-pi num-trials) (define (in-unit-circle? x y) (< (+ (sqr x) (sqr y)) 1)) (estimate-integral in-unit-circle? -1 1 -1 1 num-trials)) ;; tests (estimate-pi 10) ;; 3.6 (estimate-pi 100) ;; 3.2 (estimate-pi 1000) ;; 3.176 (estimate-pi 10000) ;; 3.1492 (estimate-pi 100000) ;; 3.14252 (estimate-pi 1000000) ;; 3.14344 ;;;;;;;;; ;; 3.6 ;; ;;;;;;;;; ;; We'll use our own very simple prng: x[n+1] = 23 * x[n] + 11 mod 493. (define (make-resettable-prng seed) (define (rand-update x) (remainder (+ (* 23 x) 11) 493)) (define x seed) (lambda (m) (cond [(eq? m 'generate) (set! x (rand-update x)) x] [(eq? m 'reset) (set! x seed) "Reset."] [else "Unknown request -- RAND"]))) (define new-prng (make-resettable-prng 10)) ;; tests (new-prng 'generate) ;; 241 (new-prng 'generate) ;; 131 (new-prng 'generate) ;; 66 (new-prng 'reset) ;; "Reset." (new-prng 'generate) ;; 241 (new-prng 'generate) ;; 131 (new-prng 'generate) ;; 66 ;;;;;;;;; ;; 3.7 ;; ;;;;;;;;; (define (make-joint account password new-password) (if (number? ((account password 'deposit) 0)) ; deposit 0 to check original pw (lambda (pass m) (if (eq? pass new-password) (account password m) (display-error "Incorrect password"))) "Password does not match -- MAKE-JOINT")) (define paul-acc (make-account 100 'abc)) ((paul-acc 'abc 'deposit) 100) ;; 200 (define mary-acc (make-joint paul-acc 'abc 'def)) ((mary-acc 'def 'withdraw) 75) ;; 125 ((mary-acc 'def 'deposit) 50) ;; 175 ((mary-acc 'xyz 'withdraw) 1000000) ;; "Incorrect password" (make-joint mary-acc 'xyz 'def) ;; "Password does not match -- MAKE-JOINT" ;;;;;;;;; ;; 3.8 ;; ;;;;;;;;; (define (make-weird-function) (define state 0) (lambda (n) (cond [(and (even? state) (even? n)) (set! state (add1 state)) -1] [(and (odd? state) (odd? n)) (set! state (add1 state)) 1] [(and (even? state) (odd? n)) (set! state (add1 state)) 1] [(and (odd? state) (even? n)) (set! state (add1 state)) 0]))) ;; test (define f (make-weird-function)) (f 0) ;; -1 (f 1) ;; 1 ;; So evaluating (+ (f 0) (f 1)) left to right would produce (+ -1 1) or zero. (define g (make-weird-function)) (g 1) ;; 1 (g 0) ;; 0 ;; So evaluating (+ (g 0) (g 1)) right to left would produce (+ 1 0) or one.