|
| 1 | +;; Helpers |
| 2 | +(define (say input) (display input) (newline)) |
| 3 | + |
| 4 | +;; 3.0 Modularity, objects and state |
| 5 | +;; We need strategies to help us structure large systems, so that they will be |
| 6 | +;; modular. So that they can be divided naturally into coherent parts that can |
| 7 | +;; be separately developed and maintained. |
| 8 | +;; We do this by basing the structure of our programs on the structure of the |
| 9 | +;; system being modeled. For each object in the system we construct a |
| 10 | +;; corresponding computational object. For each system action we define a |
| 11 | +;; symbolic operation in our computational model. In this chapter we will |
| 12 | +;; investigate two prominent organizational strategies arising from two rather |
| 13 | +;; different world views of the structure of systems: |
| 14 | +;; - concentrating on objects (system is a collection of objects whose behaviour |
| 15 | +;; changes over time) |
| 16 | +;; - concentrating on streams of information that flow in the system, much as a |
| 17 | +;; signal-processing system |
| 18 | + |
| 19 | + |
| 20 | +;; 3.1 Assignment and local state |
| 21 | +;; We can characterize an objects state by one or more state variables, which |
| 22 | +;; maintain enough information about history to determine the objects current |
| 23 | +;; behaviour. In a simple banking system we could characterize the state of an |
| 24 | +;; account by a current balance rather than by remembering the entire history |
| 25 | +;; of account transactions. |
| 26 | +;; In a system composed of many objects, the objects are rarely completly |
| 27 | +;; independent. Each can influence the states of others through interactions, |
| 28 | +;; which serve to couple the state variables of one object to those of other |
| 29 | +;; objects. |
| 30 | +;; For a system model to be modular it should be decomposed into computational |
| 31 | +;; objects that model the actual objects in the system. Each computational object |
| 32 | +;; must have its own local state variables, describing the objects actual state. |
| 33 | +;; Since the state of objects in the system changes over time, the state variables |
| 34 | +;; of corresponding computational objects must also change. The language must |
| 35 | +;; provide an assignment operator to enable us to change the value associated |
| 36 | +;; with the name. |
| 37 | + |
| 38 | +;; 3.1.1 Local state variables |
| 39 | +;; To ilustrate the idea of a computational object with time-varying state, let |
| 40 | +;; us model the situaton of withdrawing money from a bank account. We will do |
| 41 | +;; this using the procedure withdraw, which takes as an argument the amount to |
| 42 | +;; be withdrawn. If there is enough money in the account to accomodate the |
| 43 | +;; withdrawal, then withdraw should return the balance remaining after the |
| 44 | +;; withdrawal. Otherwise it should return the message 'Insufficient funds'. |
| 45 | +;; To implement withdrawal we can use a variable 'balance' to indicate the |
| 46 | +;; balance of money in the account and define withdraw as a procedure that |
| 47 | +;; accesses 'balance'. It checks if balance is at least as large as the requested |
| 48 | +;; amount. If so, it decrements balance by amount and returns the new value of |
| 49 | +;; balance. |
| 50 | +(define balance 100) |
| 51 | + |
| 52 | +(define (withdraw amount) |
| 53 | + (if (>= balance amount) |
| 54 | + ;; set! changes 'balance' so that new value is the result of |
| 55 | + ;; evaluating given expression |
| 56 | + (begin (set! balance (- balance amount)) |
| 57 | + balance) |
| 58 | + "Insufficient funds")) |
| 59 | +;; The procedure uses the 'begin' special form to cause two expressions to be |
| 60 | +;; evaluated in the case where test is true. The value of the final expression |
| 61 | +;; is returned as the value of the entire begin form. |
| 62 | + |
| 63 | +;; The balance variable presents a problem. It is defined in the global environment |
| 64 | +;; and is freely accessible to be examined or modified by any procedure. It would |
| 65 | +;; be much better if we could make balance internal to withdraw, so that any other |
| 66 | +;; procedure could accesses balance only through calls to withdraw (indirectly). |
| 67 | +(define (make-withdrawal balance) |
| 68 | + (lambda (amount) |
| 69 | + (if (>= balance amount) |
| 70 | + (begin (set! balance (- balance amount)) |
| 71 | + balance) |
| 72 | + "Insufficient funds!"))) |
| 73 | +;; make-withdrawal can be used as follows to create two objects: |
| 74 | +(define w1 (make-withdrawal 100)) |
| 75 | +(define w2 (make-withdrawal 150)) |
| 76 | +;; Observe that w1 and w2 are completely independent objects, each with its own |
| 77 | +;; local state variable balance. Withdrawals from one do not affect the other: |
| 78 | + |
| 79 | +;; Representing simple bank accounts boils down to making deposits as well as |
| 80 | +;; withdrawals. Here is a procedure that returns a 'bank account object': |
| 81 | +(define (make-account balance) |
| 82 | + (define (withdraw amount) |
| 83 | + (if (>= balance amount) |
| 84 | + (begin (set! balance (- balance amount)) |
| 85 | + balance) |
| 86 | + "Insufficient funds!")) |
| 87 | + |
| 88 | + (define (deposit amount) |
| 89 | + (if (> amount 0) |
| 90 | + (begin (set! balance (+ balance amount)) |
| 91 | + balance) |
| 92 | + "Incorrect amount!")) |
| 93 | + |
| 94 | + (lambda (m . a) |
| 95 | + (cond ((eq? m 'w) (withdraw (car a))) |
| 96 | + ((eq? m 'd) (deposit (car a))) |
| 97 | + (else (say "Unknown request!"))))) |
| 98 | + |
| 99 | +;; Each call to make-account creates an object with a local state variable |
| 100 | +;; 'balance'. The internal procedures access this variable and manipulate it. |
| 101 | +;; The object takes a 'message' as the input and returns one of the two local |
| 102 | +;; procedures. |
| 103 | +;;(define acc1 (make-account 100)) |
| 104 | +;;(say (acc1 'w 50)) |
| 105 | +;;(say (acc1 'd 150)) |
| 106 | +;;(say (acc1 'w 1000)) |
| 107 | +;; Another call to make-account will produce a completly separate account object |
| 108 | +;; which maintains its own local balance. |
| 109 | + |
| 110 | +;; Exercise 3.1 |
| 111 | +;; Write an accumulator - a procedure that is called repeatedly with a single |
| 112 | +;; numeric argument and accumulates its arguments into a sum. |
| 113 | +(define (make-accumulator sum) |
| 114 | + (lambda (amount) |
| 115 | + (if (symbol? amount) |
| 116 | + "Incorrect input value!" |
| 117 | + (begin (set! sum (+ sum amount)) |
| 118 | + sum)))) |
| 119 | + |
| 120 | +;;(define A1 (make-accumulator 5)) |
| 121 | +;;(say (A1 10)) |
| 122 | +;;(say (A1 10)) |
| 123 | +;;(say (A1 -100)) |
| 124 | +;;(say (A1 'qwwe)) |
| 125 | + |
| 126 | + |
| 127 | +;; Exercise 3.2 |
| 128 | +;; Count the number of times a given procedure is called. Write a procedure |
| 129 | +;; 'make-monitored' that takes as input a procedure 'f', that itself takes input. |
| 130 | +;; The result returned by make-monitored is an object, that takes track of the |
| 131 | +;; number of times it has been called by maintaining an internal counter. |
| 132 | +;; If the input is: |
| 133 | +;; - 'how-many-calls? : return the value of the counter |
| 134 | +;; - 'reset-count : resets the counter to 0 |
| 135 | +;; - other input ; result of calling 'f' with that input and increments |
| 136 | +;; the counter |
| 137 | +(define (make-monitored f) |
| 138 | + (let ((how-many-calls 0)) |
| 139 | + (lambda (input) |
| 140 | + (cond ((and (symbol? input) |
| 141 | + (eq? input 'how-many-calls?)) |
| 142 | + how-many-calls) |
| 143 | + ((and (symbol? input) |
| 144 | + (eq? input 'reset-count)) |
| 145 | + (set! how-many-calls 0)) |
| 146 | + (else (begin (set! how-many-calls (+ how-many-calls 1)) |
| 147 | + (f input))))))) |
| 148 | + |
| 149 | +;;(define monitor-sqrt (make-monitored sqrt)) |
| 150 | +;;(say (monitor-sqrt 'how-many-calls?)) |
| 151 | +;;(say (monitor-sqrt 10)) |
| 152 | +;;(say (monitor-sqrt 5)) |
| 153 | +;;(say (monitor-sqrt 'how-many-calls?)) |
| 154 | +;;(say (monitor-sqrt 'reset-count)) |
| 155 | +;;(say (monitor-sqrt 'how-many-calls?)) |
| 156 | + |
| 157 | +;; Exercise 3.3 abd 3.4 HAHAHAHA :-) |
| 158 | + |
| 159 | + |
| 160 | +;; 3.1.2 Benefits of introducing assignment |
| 161 | +;; To realize the annoyance that would be to explicitly remember the current |
| 162 | +;; value of 'x' passed as an argument to 'random-update', we will consider |
| 163 | +;; using random numbers to implement a technique called Monte Carlo simulation |
| 164 | +;; (YAY! :/). |
| 165 | + |
| 166 | +;; Quote: |
| 167 | +;; "The Monte Carlo method consists of choosing sample experiments at random from |
| 168 | +;; a large set and then making deductions on the basis of the probabilities |
| 169 | +;; estimated from tabulating the results of those experiments." |
| 170 | +;; I don't get it ... |
0 commit comments