├── 4.3 ├── 4.3.scm └── notes.md ├── 5.4 ├── notes.md ├── e-5.25.scm ├── e-5.28.scm ├── load-eceval.scm ├── load-eceval-non-tail-recursive.scm ├── e-5.23.scm ├── e-5.27.scm ├── e-5.29.scm └── e-5.26.scm ├── 5.1 ├── e-5.1.png ├── e-5.2.scm ├── e-5.1.scm ├── e-5.6.scm ├── e-5.5.scm ├── notes.md └── e-5.4.scm ├── 5.3 ├── e-5.20.png ├── e-5.20.scm └── notes.md ├── 1.2 ├── e-1.13.scm ├── e-1.21.scm ├── e-1.12.scm ├── e-1.9.scm ├── e-1.17.scm ├── e-1.16.scm ├── e-1.26.scm └── e-1.18.scm ├── 1.1 ├── e-1.2.scm ├── e-1.4.scm ├── e-1.3.scm ├── 1.1.scm ├── e-1.5.scm ├── e-1.8.scm └── e-1.6.scm ├── helpers.scm ├── 4.2 ├── e-4.32.scm ├── lazy-streams.scm ├── e-4.28.scm ├── e-4.25.scm ├── e-4.29.scm ├── notes.md └── e-4.27.scm ├── 3.5 ├── e-3.65.scm ├── e-3.53.scm ├── e-3.55.scm ├── e-3.54.scm ├── e-3.58.scm ├── e-3.79.scm ├── e-3.78.scm ├── e-3.68.scm ├── e-3.50.scm ├── e-3.57.scm ├── e-3.64.scm ├── e-3.61.scm ├── e-3.63.scm ├── e-3.69.scm ├── e-3.76.scm ├── e-3.62.scm ├── e-3.67.scm ├── series.scm ├── e-3.80.scm ├── e-3.51.scm ├── e-3.72.scm ├── e-3.77.scm ├── e-3.71.scm ├── e-3.75.scm └── e-3.60.scm ├── 4.1 ├── e-4.22.scm ├── e-4.24.scm ├── notes.md ├── e-4.14.scm ├── e-4.10.scm ├── e-4.11.scm ├── e-4.13.scm ├── e-4.21.scm ├── e-4.17.scm ├── e-4.7.scm ├── e-4.18.scm ├── e-4.9.scm └── e-4.15.scm ├── 2.2 ├── e-2.44.scm ├── e-2.35.scm ├── e-2.26.scm ├── e-2.17.scm ├── e-2.39.scm ├── e-2.52.scm ├── e-2.28.scm ├── e-2.25.scm ├── e-2.48.scm ├── e-2.40.scm ├── e-2.45.scm ├── e-2.21.scm ├── e-2.24.scm ├── e-2.50.scm ├── e-2.33.scm ├── e-2.30.scm ├── e-2.27.scm ├── e-2.23.scm ├── e-2.32.scm ├── e-2.18.scm ├── e-2.34.scm ├── e-2.31.scm ├── e-2.47.scm ├── e-2.46.scm ├── e-2.36.scm ├── e-2.49.scm ├── e-2.41.scm └── e-2.51.scm ├── 1.3 ├── e-1.35.scm ├── e-1.41.scm ├── e-1.34.scm ├── e-1.42.scm ├── e-1.40.scm ├── e-1.38.scm ├── e-1.30.scm ├── e-1.43.scm ├── e-1.44.scm ├── e-1.39.scm └── e-1.31.scm ├── 2.1 ├── e-2.8.scm ├── e-2.1.scm ├── e-2.16.scm ├── e-2.7.scm ├── e-2.12.scm ├── e-2.13.scm ├── e-2.15.scm ├── e-2.10.scm ├── e-2.4.scm └── e-2.6.scm ├── 4.4 ├── e-4.55.scm ├── e-4.56.scm └── e-4.57.scm ├── 2.3 ├── e-2.71.scm ├── e-2.55.scm ├── e-2.61.scm ├── e-2.67.scm ├── e-2.59.scm ├── e-2.53.scm ├── e-2.72.scm ├── e-2.54.scm ├── e-2.62.scm └── e-2.56.scm ├── 5.5 ├── code-formatter.scm ├── e-5.37.scm └── e-5.36.scm ├── 3.4 ├── e-3.49.scm ├── e-3.43.scm ├── e-3.44.scm ├── e-3.40.scm ├── e-3.39.scm ├── e-3.38.scm ├── e-3.46.scm └── e-3.42.scm ├── 5.2 ├── e-5.13.scm ├── e-5.10.scm ├── e-5.7.scm ├── e-5.9.scm └── e-5.8.scm ├── debug.scm ├── 3.3 ├── e-3.15.scm ├── e-3.28.scm ├── e-3.33.scm ├── e-3.13.scm ├── e-3.34.scm ├── e-3.37.scm ├── e-3.29.scm ├── e-3.31.scm ├── e-3.14.scm ├── e-3.36.scm ├── 3.3.scm ├── e-3.16.scm ├── e-3.18.scm ├── e-3.32.scm └── e-3.35.scm ├── 2.5 ├── e-2.89.scm ├── notes.md ├── e-2.80.scm ├── e-2.86.scm ├── e-2.87.scm ├── e-2.83.scm └── e-2.79.scm ├── 3.1 ├── e-3.8.scm ├── e-3.1.scm ├── e-3.3.scm └── e-3.4.scm ├── 2.4 └── e-2.75.scm └── 3.2 ├── e-3.9.scm ├── e-3.11.scm └── e-3.10.scm /4.3/4.3.scm: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /4.3/notes.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /5.4/notes.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /5.1/e-5.1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ivanjovanovic/sicp/HEAD/5.1/e-5.1.png -------------------------------------------------------------------------------- /5.3/e-5.20.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ivanjovanovic/sicp/HEAD/5.3/e-5.20.png -------------------------------------------------------------------------------- /1.2/e-1.13.scm: -------------------------------------------------------------------------------- 1 | ; Skipping purely mathematical exercise until it is needed for some 2 | ; other exercise. 3 | -------------------------------------------------------------------------------- /1.1/e-1.2.scm: -------------------------------------------------------------------------------- 1 | ; exercise 1.2 equation in prefix form 2 | (/ (+ 5 4 (- 2 (- 3 (+ 6 (/ 4 3))))) 3 | (* 3 (- 6 2) (- 2 7))) 4 | -------------------------------------------------------------------------------- /1.1/e-1.4.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 1.4 2 | ; Operators can be compound expressions. 3 | ; Based on the value of parameter b operator is determined. 4 | (define (a-plus-abs-b a b) 5 | ((if (> b 0) + -) a b)) 6 | -------------------------------------------------------------------------------- /helpers.scm: -------------------------------------------------------------------------------- 1 | ; helper DSL to make implementation and representation of exercises more 2 | ; enjoyable 3 | 4 | (define (output . to-print) 5 | (map (lambda (x) (display x) (newline)) to-print)) 6 | 7 | -------------------------------------------------------------------------------- /4.2/e-4.32.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 4.32. 2 | ; 3 | ; Give some examples that illustrate the difference between the 4 | ; streams of chapter 3 and the ``lazier'' lazy lists described in this section. 5 | ; How can you take advantage of this extra laziness? 6 | ; ------------------------------------------------------------ 7 | -------------------------------------------------------------------------------- /3.5/e-3.65.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 3.65. Use the series 2 | 3 | ; ln2 = 1 - 1/2 + 1/3 - 1/4 + ... 4 | 5 | ; to compute three sequences of approximations to the natural logarithm 6 | ; of 2, in the same way we did above for . How rapidly do these 7 | ; sequences converge? 8 | ; ------------------------------------------------------------ 9 | -------------------------------------------------------------------------------- /1.1/e-1.3.scm: -------------------------------------------------------------------------------- 1 | ; excercise 1.3 2 | ; Define procedure that takes three numbers as arguments and returns 3 | ; the sum of the squares of the two larger numbers 4 | (define (sum-larger-square a b c) 5 | (cond ((and (< a b) (< a c)) (+ (* b b) (* c c))) 6 | ((and (< b a) (< b c)) (+ (* a a) (* c c))) 7 | (else (+ (* a a) (* b b))))) 8 | -------------------------------------------------------------------------------- /1.2/e-1.21.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 1.21. Use the smallest-divisor procedure to find the 2 | ; smallest divisor of each of the following numbers: 199, 1999, 19999. 3 | 4 | (load "1.2.scm") 5 | 6 | (display (smallest-divisor 199)) ; 199 7 | (newline) 8 | 9 | (display (smallest-divisor 1999)) ; 1999 10 | (newline) 11 | 12 | (display (smallest-divisor 19999)) ; 7 13 | (newline) 14 | -------------------------------------------------------------------------------- /4.1/e-4.22.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 4.22. 2 | ; 3 | ; Extend the evaluator in this section to support the special 4 | ; form let. (See exercise 4.6.) 5 | ; ------------------------------------------------------------ 6 | 7 | (load "e-4.6.scm") 8 | 9 | ; so, in the analyzer we just have to add a line 10 | 11 | (define (analyze exp) 12 | . 13 | . 14 | ((let? exp) (analyze (let->combination exp))) 15 | . 16 | .) 17 | -------------------------------------------------------------------------------- /2.2/e-2.44.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 2.44. Define the procedure up-split used by corner-split. It 2 | ; is similar to right-split, except that it switches the roles of below 3 | ; and beside. 4 | ; --------------------------------------------------------------------- 5 | 6 | (define (up-split painter n) 7 | (if (= n 0) 8 | painter 9 | (let ((smaller (up-split painter (- n 1)))) 10 | (below painter (beside smaller smaller))))) 11 | -------------------------------------------------------------------------------- /4.1/e-4.24.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 4.24. Design and carry out some experiments to compare the speed 2 | ; of the original metacircular evaluator with the version in this section. 3 | ; Use your results to estimate the fraction of time that is spent in analysis 4 | ; versus execution for various procedures. 5 | ; ------------------------------------------------------------ 6 | 7 | 8 | ; It is faster ... especially if you execute complex things lot of times. 9 | -------------------------------------------------------------------------------- /5.4/e-5.25.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 5.25. Modify the evaluator so that it uses normal-order 2 | ; evaluation, based on the lazy evaluator of section 4.2. 3 | ; ------------------------------------------------------------ 4 | 5 | ; At the end, this is as for all the other function just tediously 6 | ; implementing the procedures in the machine language. 7 | ; In this stadium I feel I learned enough about the evaluator and 8 | ; principles behind it to skip this exercise. 9 | -------------------------------------------------------------------------------- /1.3/e-1.35.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 1.35. 2 | ; 3 | ; Show that the golden ratio Phi (section 1.2.2) is a fixed point of the 4 | ; transformation x -> 1 + 1/x, and use this fact to compute by means of the fixed-point procedure. 5 | ; 6 | ; --------------------------- 7 | 8 | (load "1.3.scm") ; reusing fixed-point 9 | 10 | (define (phi precision) 11 | (fixed-point 12 | (lambda (x) (+ 1 (/ 1 x))) 13 | 1.0 14 | precision)) 15 | 16 | (display (phi 0.00000001)) 17 | (newline) 18 | -------------------------------------------------------------------------------- /3.5/e-3.53.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 3.53. Without running the program, describe the elements of 2 | ; the stream defined by 3 | 4 | ; (define s (cons-stream 1 (add-streams s s))) 5 | ; ------------------------------------------------------------ 6 | 7 | (load "../helpers.scm") 8 | (load "3.5.scm") 9 | 10 | (define s (cons-stream 1 (add-streams s s))) 11 | 12 | ; This produces same result as doubling the stream. 13 | ; It makes every next element twice of the previous one 14 | 15 | (output (stream-ref s 6)) ; 64 16 | -------------------------------------------------------------------------------- /2.1/e-2.8.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 2.8. 2 | ; 3 | ; Using reasoning analogous to Alyssa's, describe how the difference of two 4 | ; intervals may be computed. Define a corresponding subtraction procedure, called sub-interval. 5 | ; ------------------------------------- 6 | 7 | (load "2.1.scm") 8 | (load "e-2.7.scm") 9 | 10 | (define (sub-interval x y) 11 | (make-interval (- (lower-bound x) (lower-bound y)) 12 | (- (upper-bound x) (upper-bound y)))) 13 | 14 | ; (display (lower-bound (sub-interval r2 r1))) 15 | ; (newline) 16 | -------------------------------------------------------------------------------- /4.4/e-4.55.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 4.55. Give simple queries that retrieve the following 2 | ; information from the data base: 3 | 4 | ; a. all people supervised by Ben Bitdiddle; 5 | ; b. the names and jobs of all people in the accounting division; 6 | ; c. the names and addresses of all people who live in Slumerville. 7 | ; ------------------------------------------------------------- 8 | 9 | ; a) (supervisor (Ben Bitdiddle) ?name) 10 | ; 11 | ; b) (job ?name (accounting . ?skills)) 12 | ; 13 | ; c) (address ?name (Slumerville . ?address)) 14 | -------------------------------------------------------------------------------- /5.1/e-5.2.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 5.2. Use the register-machine language to describe the 2 | ; iterative factorial machine of exercise 5.1. 3 | ; ------------------------------------------------------------ 4 | 5 | (controller 6 | (assign N (read)) ; assuming read is given as a primitive 7 | (assign p (const 1)) 8 | (assign c (const 1)) 9 | iter 10 | (test (op >) (reg c) (reg N)) 11 | (branch (label iter-done)) 12 | (assign p (op *) (reg p) (reg c)) 13 | (assign c (op +) (reg c) (const 1)) 14 | (goto (label iter)) 15 | iter-done) 16 | -------------------------------------------------------------------------------- /2.3/e-2.71.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 2.71. 2 | ; 3 | ; Suppose we have a Huffman tree for an alphabet of n symbols, 4 | ; and that the relative frequencies of the symbols are 1, 2, 4, ..., 2n-1. 5 | ; Sketch the tree for n=5; for n=10. In such a tree (for general n) how many 6 | ; bits are required to encode the most frequent symbol? the least frequent 7 | ; symbol? 8 | ; ------------------------------------------------------------ 9 | 10 | ; Tree is easy to scetch. 11 | ; 12 | ; For the biggest weight symbol, it will take always only 1, 13 | ; and for the smallest weight n-1 bits. 14 | -------------------------------------------------------------------------------- /5.5/code-formatter.scm: -------------------------------------------------------------------------------- 1 | ; helper procedure to output formatted object code 2 | (define (format-object-code object-code) 3 | (if (not (null? object-code)) 4 | (let ((instruction (car object-code))) 5 | (if (symbol? instruction) 6 | (begin 7 | (output instruction) ; label 8 | (format-object-code (cdr object-code))) 9 | (begin 10 | (display " ") (output instruction) ; indented 11 | (format-object-code (cdr object-code))))) 12 | 'done)) 13 | 14 | (define (instruction-list object-code) (caddr object-code)) 15 | -------------------------------------------------------------------------------- /2.3/e-2.55.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 2.55. 2 | ; 3 | ; Eva Lu Ator types to the interpreter the expression 4 | 5 | ; (car ''abracadabra) 6 | 7 | ; To her surprise, the interpreter prints back quote. Explain. 8 | ;------------------------------------------------------------ 9 | 10 | ; apostrophe is just symbol representing the procedure (quote), so when we expand this 11 | ; we'll get something like 12 | 13 | (car (quote (quote abasdfa))) 14 | 15 | ; which is 16 | 17 | (car '(quote asfasd)) 18 | 19 | ; whose output is as stated 20 | 21 | (display (car '(quote asdfasdf))) ; > quote 22 | -------------------------------------------------------------------------------- /1.3/e-1.41.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 1.41. 2 | ; 3 | ; Define a procedure double that takes a procedure of one argument 4 | ; as argument and returns a procedure that applies the original procedure 5 | ; twice. For example, if inc is a procedure that adds 1 to its argument, 6 | ; then (double inc) should be a procedure that adds 2. What value is returned by 7 | ; 8 | ; (((double (double double)) inc) 5) 9 | 10 | (load "../common.scm") 11 | 12 | (define (double f) 13 | (lambda (x) 14 | (f (f x)))) 15 | 16 | ; (display (((double (double double)) inc) 5)) ; result is 21 17 | ; (newline) 18 | -------------------------------------------------------------------------------- /3.4/e-3.49.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 3.49. 2 | ; 3 | ; Give a scenario where the deadlock-avoidance mechanism 4 | ; described above does not work. (Hint: In the exchange problem, each 5 | ; process knows in advance which accounts it will need to get access to. 6 | ; Consider a situation where a process must get access to some shared 7 | ; resources before it can know which additional shared resources it will 8 | ; require.) 9 | ; ------------------------------------------------------------ 10 | 11 | ; brainstorming problem. There are various ways to think of it and to 12 | ; find lot of ways it will not work. 13 | -------------------------------------------------------------------------------- /4.2/lazy-streams.scm: -------------------------------------------------------------------------------- 1 | ; Based on the lazy evaluation of procedure arguments, we can implement 2 | ; list abstraction so they are naturally lazy. We just have to implement 3 | ; pair as a procedure that will represent them and selectors just as 4 | ; applications of this procedure. 5 | 6 | (define (cons x y) (lambda (m) (m x y))) 7 | (define (car z) (z (lambda (p q) p))) 8 | (define (cdr z) (z (lambda (p q) q))) 9 | 10 | ; When defined this way in a lazy language, lists are even lazier than streams. Streams 11 | ; have car always as immediate value, and here we have even car value as thunk that has 12 | ; to be forced. 13 | -------------------------------------------------------------------------------- /4.2/e-4.28.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 4.28. 2 | ; 3 | ; Eval uses actual-value rather than eval to evaluate 4 | ; the operator before passing it to apply, in order to force the value 5 | ; of the operator. Give an example that demonstrates the need for this 6 | ; forcing. 7 | ; ------------------------------------------------------------ 8 | 9 | ; whenever the operator is to be resolved by evaluation instead 10 | ; given directly. For example, if (deposit account) would return the 11 | ; procedure that does deposit we would need to have it evaluated before 12 | ; application and not treated as a thunk: 13 | ; 14 | ; ((deposit account) 100) 15 | -------------------------------------------------------------------------------- /1.3/e-1.34.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 1.34. 2 | ; 3 | ; Suppose we define the procedure 4 | 5 | (load "../common.scm") 6 | 7 | (define (f g) 8 | (g 2)) 9 | 10 | ; Then we have 11 | 12 | (display (f square)) ; 4 13 | (newline) 14 | 15 | (display (f (lambda (z) (* z (+ z 1))))) ; 6 16 | (newline) 17 | 18 | ; What happens if we (perversely) ask the interpreter to 19 | ; evaluate the combination (f f)? Explain. 20 | ; 21 | ; -------------------------------------------------- 22 | 23 | (f f) 24 | 25 | ; (f f) - will evaluate to 26 | ; (f 2) - will evaluate to 27 | ; (2 2) - will throw error because it expects first term to be procedure 28 | 29 | 30 | -------------------------------------------------------------------------------- /3.5/e-3.55.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 3.55. 2 | ; 3 | ; Define a procedure partial-sums that takes as argument 4 | ; a stream S and returns the stream whose elements are S0, S0 + S1, S0 + 5 | ; S1 + S2, .... For example, (partial-sums integers) should be the 6 | ; stream 1, 3, 6, 10, 15, .... 7 | ; ------------------------------------------------------------ 8 | 9 | 10 | (load "../helpers.scm") 11 | (load "3.5.scm") 12 | 13 | (define (partial-sums stream) 14 | (cons-stream (stream-car stream) 15 | (add-streams (partial-sums stream) (stream-cdr stream)))) 16 | 17 | (display-stream (partial-sums integers)) ; 1 3 6 10 15 21 28 36 45 55 ... 18 | -------------------------------------------------------------------------------- /5.2/e-5.13.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 5.13. Modify the simulator so that it uses the controller 2 | ; sequence to determine what registers the machine has rather than 3 | ; requiring a list of registers as an argument to make-machine. Instead 4 | ; of pre-allocating the registers in make-machine, you can allocate them 5 | ; one at a time when they are first seen during assembly of the 6 | ; instructions. 7 | ; ------------------------------------------------------------ 8 | 9 | ; This is not so difficult task. 10 | ; 11 | ; First hint is to update get-register-content and set-register-content 12 | ; to create the register if there is no one already. 13 | 14 | -------------------------------------------------------------------------------- /5.1/e-5.1.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 5.1. Design a register machine to compute factorials using 2 | ; the iterative algorithm specified by the following procedure. Draw 3 | ; data-path and controller diagrams for this machine. 4 | 5 | (define (factorial n) 6 | (define (iter product counter) 7 | (if (> counter n) 8 | product 9 | (iter (* counter product) 10 | (+ counter 1)))) 11 | (iter 1 1)) 12 | 13 | ; ------------------------------------------------------------ 14 | 15 | ; Here is in fact the most important do design the internal iterative 16 | ; process. My solution is given in the scan e-5.1.png in the same 17 | ; folder. 18 | -------------------------------------------------------------------------------- /2.3/e-2.61.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 2.61. 2 | ; 3 | ; Give an implementation of adjoin-set using the ordered 4 | ; representation. By analogy with element-of-set? show how to take 5 | ; advantage of the ordering to produce a procedure that requires on the 6 | ; average about half as many steps as with the unordered representation. 7 | ; ------------------------------------------------------------ 8 | 9 | ; adjoin set that makes ordered set of numbers as output 10 | (define (adjoin-set x set) 11 | (cond ((null? set) (list x)) 12 | ((= x (car set)) set) 13 | ((< x (car set) (cons x set))) 14 | (else (cons (car set) (adjoin-set x (cdr set)))))) 15 | -------------------------------------------------------------------------------- /1.3/e-1.42.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 1.42. 2 | ; 3 | ; Let f and g be two one-argument functions. The composition f after g is defined 4 | ; to be the function x -> f(g(x)). Define a procedure compose that implements composition. 5 | ; For example, if inc is a procedure that adds 1 to its argument, 6 | ; 7 | ; ((compose square inc) 6) to give 49 as result 8 | ; 9 | ; ------------------------------------------------- 10 | 11 | (load "../common.scm") 12 | 13 | ; here we produce composition procedure as defined in task 14 | (define (compose f g) 15 | (lambda (x) 16 | (f (g x)))) 17 | 18 | ; (display ((compose square inc) 6)) ; gives 49 as result 19 | ; (newline) 20 | 21 | -------------------------------------------------------------------------------- /2.2/e-2.35.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 2.35. 2 | ; 3 | ; Redefine count-leaves from section 2.2.2 as an accumulation: 4 | 5 | ; (define (count-leaves t) 6 | ; (accumulate (map ))) 7 | ; -------------------------------------------------------- 8 | 9 | (load "../common.scm") 10 | (load "../helpers.scm") 11 | (load "2.2.scm") 12 | 13 | (define (count-leaves tree) 14 | (accumulate 15 | + 0 16 | (map 17 | (lambda (x) 1) ; for every element just return binary existence 18 | (enumerate-leaves tree)))) ; enumerate all the leaves 19 | 20 | ; this gives 9 as expected 21 | (output (count-leaves (list 1 2 (list 3 4 5) 4 5 (list 1 (list 3))))) 22 | -------------------------------------------------------------------------------- /debug.scm: -------------------------------------------------------------------------------- 1 | (define *log-level* 3) 2 | 3 | (define (set-minimum-log-level level) 4 | (cond ((eq? level 'DEBUG) (set! *log-level* 1)) 5 | ((eq? level 'INFO) (set! *log-level* 2)) 6 | ((eq? level 'WARN) (set! *log-level* 3)) 7 | ((eq? level 'ERROR) (set! *log-level* 4)))) 8 | 9 | (define (logger level . msgs) 10 | (if (<= *log-level* level) 11 | (begin 12 | (map display (cons msgs " ")) 13 | (newline)))) 14 | 15 | (define (debug-log . msgs) (logger 1 'DEBUG msgs)) 16 | (define (info-log . msgs) (logger 2 'INFO msgs)) 17 | (define (warn-log . msgs) (logger 3 'WARN msgs)) 18 | (define (err-log . msgs) (logger 4 'ERROR msgs)) 19 | -------------------------------------------------------------------------------- /2.2/e-2.26.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 2.26. 2 | ; Suppose we define x and y to be two lists: 3 | 4 | (define x (list 1 2 3)) 5 | (define y (list 4 5 6)) 6 | 7 | ; What result is printed by the interpreter in response to evaluating each of the following expressions: 8 | 9 | ; (append x y) 10 | 11 | ; (cons x y) 12 | 13 | ; (list x y) 14 | ; -------------------------------------- 15 | 16 | ; without calculation I suppose it should be 17 | ; 18 | ; 1) (1 2 3 4 5 6) 19 | ; 2) ((1 2 3) 4 5 6) 20 | ; 3) ((1 2 3) (4 5 6)) 21 | 22 | ; and lets check if that is true 23 | 24 | (load "../helpers.scm") 25 | 26 | (output (append x y)) 27 | (output (cons x y)) 28 | (output (list x y)) 29 | 30 | -------------------------------------------------------------------------------- /5.2/e-5.10.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 5.10. 2 | ; 3 | ; Design a new syntax for register-machine instructions and 4 | ; modify the simulator to use your new syntax. Can you implement your new 5 | ; syntax without changing any part of the simulator except the syntax 6 | ; procedures in this section? 7 | ; ------------------------------------------------------------ 8 | 9 | ; This is more or less repetition of the concept introduced with the 10 | ; metalingustic abstractions. It is possible to isolate the way language of the 11 | ; controller looks like and how it is executed in the register machine and to 12 | ; change its syntax only with small modifications in the syntax related procedures. 13 | -------------------------------------------------------------------------------- /5.4/e-5.28.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 5.28. 2 | ; 3 | ; Modify the definition of the evaluator by changing 4 | ; eval-sequence as described in section 5.4.2 so that the evaluator is no 5 | ; longer tail-recursive. Rerun your experiments from exercises 5.26 and 5.27 6 | ; to demonstrate that both versions of the factorial procedure now require 7 | ; space that grows linearly with their input. 8 | ; ------------------------------------------------------------ 9 | ; 10 | ; For doing this exercise use ch5-eceval-non-tail-recursive.scm 11 | 12 | ; what we see here is that now even the iterative process doesn't take 13 | ; constant stack space but it grows lineraly as with the recursive process. 14 | -------------------------------------------------------------------------------- /5.3/e-5.20.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 5.20. Draw the box-and-pointer representation and the 2 | ; memory-vector representation (as in figure 5.14) of the list structure 3 | ; produced by 4 | 5 | (define x (cons 1 2)) 6 | (define y (list x x)) 7 | 8 | ; with the free pointer initially p1. What is the final value of free ? 9 | ; What pointers represent the values of x and y ? 10 | ; ------------------------------------------------------------ 11 | 12 | ; There is a PNG drawing of the memory layout for the creation of these 13 | ; two objects x and y. 14 | ; 15 | ; I start counting from 0 and at the end free register should point to 16 | ; the fourth place in the array which is indexed with the number 3. 17 | -------------------------------------------------------------------------------- /5.4/load-eceval.scm: -------------------------------------------------------------------------------- 1 | ;;;; LOADS THE EXPLICIT-CONTROL EVALUATOR FROM SECTION 5.4 OF 2 | ;;;; STRUCTURE AND INTERPRETATION OF COMPUTER PROGRAMS, WITH 3 | ;;;; ALL THE SUPPORTING CODE IT NEEDS IN ORDER TO RUN. 4 | 5 | ;;;; **NB** The actual "load" calls are implementation dependent. 6 | 7 | (load "ch5-regsim") ;reg machine simulator 8 | 9 | ;; **NB** next file contains another "load" 10 | (load "ch5-eceval-support") ;simulation of machine operations 11 | 12 | (load "ch5-eceval-original") ;eceval itself 13 | 14 | 15 | 16 | ; start the machine and define what global environment means 17 | (load "../common.scm") 18 | (define the-global-environment (setup-environment)) 19 | (start eceval) 20 | -------------------------------------------------------------------------------- /2.3/e-2.67.scm: -------------------------------------------------------------------------------- 1 | (load "example-huffman.scm") 2 | 3 | ; Exercise 2.67. 4 | ; 5 | ; Define an encoding tree and a sample message: 6 | 7 | (define sample-tree 8 | (make-code-tree (make-leaf 'A 4) 9 | (make-code-tree 10 | (make-leaf 'B 2) 11 | (make-code-tree (make-leaf 'D 1) 12 | (make-leaf 'C 1))))) 13 | 14 | (define sample-message '(0 1 1 0 0 1 0 1 0 1 1 1 0)) 15 | 16 | ; Use the decode procedure to decode the message, and give the result. 17 | ; ------------------------------------------------------------ 18 | 19 | (load "../helpers.scm") 20 | 21 | (output (decode sample-message sample-tree)) ; (A D A B B C A) 22 | -------------------------------------------------------------------------------- /2.1/e-2.1.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 2.1. 2 | ; 3 | ; Define a better version of make-rat that handles both positive and negative arguments. 4 | ; make-rat should normalize the sign so that if the rational number is positive, both the numerator and 5 | ; denominator are positive, and if the rational number is negative, only the numerator is negative. 6 | 7 | (load "2.1.scm") 8 | 9 | ; very simple solution to this problem which normalizes the minus sign 10 | ; as required 11 | ; 12 | ; 13 | (define (make-rat n d) 14 | (if (< d 0) 15 | (cons (- n) (- d)) 16 | (cons n d))) 17 | 18 | (print-rat (make-rat 1 2)) 19 | (print-rat (make-rat -1 2)) 20 | (print-rat (make-rat 1 -2)) 21 | (print-rat (make-rat -1 -2)) 22 | 23 | -------------------------------------------------------------------------------- /3.3/e-3.15.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 3.15. Draw box-and-pointer diagrams to explain the effect of 2 | ; set-to-wow! on the structures z1 and z2 above. 3 | ; ------------------------------------------------------------ 4 | 5 | ; I will not draw them here, but I did them on paper. Could have scanned 6 | ; them if my handwriting is not destroyed by typing :) 7 | 8 | ; In case of z1, both car and cdr point to the same x and therefor 9 | ; when rendering output of z2 we wil see 10 | ; ((wow b) wow b) 11 | ; 12 | ; In case of z2 both car and cdr values point to the same symbo, but as 13 | ; soon as we change one, they will just point to the different symbols, 14 | ; but car and cdr pointers will still point ot different objects. 15 | -------------------------------------------------------------------------------- /5.4/load-eceval-non-tail-recursive.scm: -------------------------------------------------------------------------------- 1 | ;;;; LOADS THE EXPLICIT-CONTROL EVALUATOR FROM SECTION 5.4 OF 2 | ;;;; STRUCTURE AND INTERPRETATION OF COMPUTER PROGRAMS, WITH 3 | ;;;; ALL THE SUPPORTING CODE IT NEEDS IN ORDER TO RUN. 4 | 5 | ;;;; **NB** The actual "load" calls are implementation dependent. 6 | 7 | (load "ch5-regsim") ;reg machine simulator 8 | 9 | ;; **NB** next file contains another "load" 10 | (load "ch5-eceval-support") ;simulation of machine operations 11 | 12 | (load "ch5-eceval-non-tail-optimized") ;eceval itself 13 | 14 | 15 | 16 | ; start the machine and define what global environment means 17 | (load "../common.scm") 18 | (define the-global-environment (setup-environment)) 19 | (start eceval) 20 | -------------------------------------------------------------------------------- /3.5/e-3.54.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 3.54. Define a procedure mul-streams, analogous to 2 | ; add-streams, that produces the elementwise product of its two input 3 | ; streams. Use this together with the stream of integers to complete the 4 | ; following definition of the stream whose nth element (counting from 0) 5 | ; is n + 1 factorial: 6 | 7 | ; (define factorials (cons-stream 1 (mul-streams ))) 8 | ; ------------------------------------------------------------ 9 | 10 | (load "../helpers.scm") 11 | (load "3.5.scm") 12 | 13 | (define (mul-streams s1 s2) 14 | (stream-map * s1 s2)) 15 | 16 | (define factorial (cons-stream 1 (mul-streams factorial (stream-cdr integers)))) 17 | 18 | (output (stream-ref factorial 3)) 19 | -------------------------------------------------------------------------------- /3.5/e-3.58.scm: -------------------------------------------------------------------------------- 1 | (load "../helpers.scm") 2 | (load "3.5.scm") 3 | 4 | ; Exercise 3.58. Give an interpretation of the stream computed by the 5 | ; following procedure: 6 | 7 | (define (expand num den radix) 8 | (cons-stream 9 | (quotient (* num radix) den) 10 | (expand (remainder (* num radix) den) den radix))) 11 | 12 | ; (Quotient is a primitive that returns the integer quotient of two 13 | ; integers.) What are the successive elements produced by (expand 1 7 14 | ; 10) ? What is produced by (expand 3 8 10) ? 15 | ; ------------------------------------------------------------ 16 | 17 | ; (display-stream (expand 1 7 10)) ; 1 4 2 8 5 7 1 4 2 8 .. 18 | 19 | ; (display-stream (expand 3 8 10)) ; 3 7 5 0 0 0 0 0 0 0 ... 20 | -------------------------------------------------------------------------------- /5.5/e-5.37.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 5.37. 2 | ; One way to understand the compiler's preserving mechanism for 3 | ; optimizing stack usage is to see what extra operations would be generated if 4 | ; we did not use this idea. Modify preserving so that it always generates the 5 | ; save and restore operations. Compile some simple expressions and identify the 6 | ; unnecessary stack operations that are generated. Compare the code to that 7 | ; generated with the preserving mechanism intact. 8 | ; ------------------------------------------------------------ 9 | 10 | ; This is easy, I will skip it since I'm eager to finish this before I go to holidays. 11 | ; In fact my wife is just packing things since our plane runs in around 24 hours ;) 12 | -------------------------------------------------------------------------------- /2.3/e-2.59.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 2.59. 2 | ; 3 | ; Implement the union-set operation for the 4 | ; unordered-list representation of sets. 5 | ; ------------------------------------------------------------ 6 | 7 | ; union set is defined as set of elements that are elements of two (or 8 | ; more) sets all together 9 | 10 | (load "../common.scm") 11 | (load "../helpers.scm") 12 | (load "2.3.scm") 13 | 14 | ; union of sets represented as unordered lists 15 | (define (union-set set1 set2) 16 | (cond ((equal? set1 '()) set2) 17 | ((not (element-of-set? (car set1) set2)) 18 | (cons (car set1) (union-set (cdr set1) set2))) 19 | (else (union-set (cdr set1) set2)))) 20 | 21 | ; (output (union-set (list 1 2 4) (list 4 5 6))) 22 | -------------------------------------------------------------------------------- /5.1/e-5.6.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 5.6. Ben Bitdiddle observes that the Fibonacci machine's 2 | ; controller sequence has an extra save and an extra restore, which can 3 | ; be removed to make a faster machine. Where are these instructions? 4 | ; ------------------------------------------------------------ 5 | 6 | ; This exercise introduces a notion of the possible optimizations in the 7 | ; machine code. It often happens that is possible to reorganize, remove 8 | ; or optimize in a different way set of instructions and not harm the 9 | ; code executed but optimize its efficiency. 10 | ; In this particular case, it is safe to remove pair of instructions 11 | ; that just put and restore something from stack without being used in 12 | ; the meantime. 13 | -------------------------------------------------------------------------------- /1.3/e-1.40.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 1.40. 2 | ; 3 | ; Define a procedure cubic that can be used together with the newtons-method 4 | ; procedure in expressions of the form 5 | ; 6 | ; (newtons-method (cubic a b c) 1) 7 | ; 8 | ; to approximate zeros of the cubic x^3 + ax^2 + bx + c. 9 | ; 10 | ; -------------------------------------------------------- 11 | 12 | 13 | (load "1.3.scm") 14 | (load "../common.scm") 15 | 16 | ; we define a procedure with three params a, b and c which will 17 | ; produce new procedure that has one argument x and will satisfy given 18 | ; expression. 19 | (define (cubic a b c) 20 | (lambda (x) 21 | (+ (cube x) (* a (square x)) (* b x) c))) 22 | 23 | ; (display (newtons-method (cubic 1 2 3) 1)) ; -1.27 approx 24 | ; (newline) 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /2.2/e-2.17.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 2.17. 2 | ; Define a procedure last-pair that returns the list that contains only the 3 | ; last element of a given (nonempty) list: 4 | ; 5 | ; Example: (last-pair (list 10 12 41 32)) -> 32 6 | ; ------------------------------------------------- 7 | 8 | (load "2.2.scm") 9 | 10 | ; 1) If I would use already defined length procedure. 11 | 12 | (define (last-pair items) 13 | (if (= (length items) 1) 14 | (car items) 15 | (last-pair (cdr items)))) 16 | 17 | (display (last-pair (list 10 12 41 32))) ; 32 18 | 19 | ; 2) Without any additional helper methods 20 | 21 | (define (last-pair items) 22 | (if (null? (cdr items)) 23 | (car items) 24 | (last-pair (cdr items)))) 25 | 26 | (display (last-pair (list 10 12 41 32))) ; 32 27 | -------------------------------------------------------------------------------- /2.2/e-2.39.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 2.39. 2 | ; 3 | ; Complete the following definitions of reverse 4 | ; (exercise 2.18) in terms of fold-right and fold-left from exercise 2.38: 5 | 6 | ; (define (reverse sequence) 7 | ; (fold-right (lambda (x y) ) nil sequence)) 8 | ; (define (reverse sequence) 9 | ; (fold-left (lambda (x y) ) nil sequence)) 10 | ; 11 | ; --------------------------------------- 12 | 13 | (load "../helpers.scm") 14 | (load "../common.scm") 15 | (load "e-2.38.scm") 16 | 17 | (define (reverse sequence) 18 | (fold-right (lambda (x y) (append y (list x))) nil sequence)) 19 | 20 | (output (reverse (list 1 2 3))) 21 | 22 | (define (reverse sequence) 23 | (fold-left (lambda (x y) (cons y x)) nil sequence)) 24 | 25 | (output (reverse (list 1 2 3))) 26 | -------------------------------------------------------------------------------- /2.5/e-2.89.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 2.89. 2 | ; 3 | ; Define procedures that implement the term-list 4 | ; representation described above as appropriate for dense polynomials. 5 | ; ------------------------------------------------------------ 6 | 7 | ; Dense polynomials do not have pairs of order and coefficient but 8 | ; only a list of terms where position in the list presents the term 9 | ; power. 10 | 11 | 12 | 13 | ; Ok, officialy I will for now not do these examples from 14 | ; 2.89 - 2.97 because it is all the same concept just broadning up, it 15 | ; is anyway extra example and I guess I got the point from this chapter. 16 | ; My goal is not to learn to implement arithmetic system in its biggest 17 | ; glory but to get the concepts and I think I have achieved that till 18 | ; now. 19 | -------------------------------------------------------------------------------- /2.3/e-2.53.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 2.53. 2 | ; 3 | ; What would the interpreter print in response to evaluating each of the following expressions? 4 | 5 | ; (list 'a 'b 'c) 6 | 7 | ; (list (list 'george)) 8 | ; (cdr '((x1 x2) (y1 y2))) 9 | 10 | ; (cadr '((x1 x2) (y1 y2))) 11 | ; (pair? (car '(a short list))) 12 | ; (memq 'red '((red shoes) (blue socks))) 13 | 14 | ; (memq 'red '(red shoes blue socks)) 15 | ; -------------------------------------------------- 16 | 17 | ; 1. (list 'a 'b 'c) > (a b c) 18 | 19 | ; 2. (cdr '((x1 x2) (y1 y2))) > ((y1 y2)) 20 | 21 | ; 3. (cadr '((x1 x2) (y1 y2))) > (y1 y2) 22 | 23 | ; 4. (pair? (car '(a short list))) > false 24 | 25 | ; 5. (memq 'red '((red shoes) (blue socks))) > false 26 | 27 | ; (memq 'red '(red shoes blue socks)) > (red shoes blue socks) 28 | -------------------------------------------------------------------------------- /2.1/e-2.16.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 2.16. 2 | ; 3 | ; Explain, in general, why equivalent algebraic expressions may lead to 4 | ; different answers. Can you devise an interval-arithmetic package that 5 | ; does not have this shortcoming, or is this task impossible? 6 | ; (Warning: This problem is very difficult.) 7 | ; -------------------------------------------------------- 8 | ; 9 | ; As explained in previous exercise, it is because different complexity 10 | ; of algebraic expression and number of times inprecise number has to be 11 | ; used as operand. Every time it is used it accumulates error. 12 | ; 13 | ; I suppose this can be fixed a bit by doing symbolic manipulation and 14 | ; simplification of the equations until they are in some appropriate 15 | ; form for most possible pricise calculations. 16 | -------------------------------------------------------------------------------- /2.2/e-2.52.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 2.52. 2 | ; 3 | ; Make changes to the square limit of wave shown in 4 | ; figure 2.9 by working at each of the levels described above. In 5 | ; particular: 6 | 7 | ; a. Add some segments to the primitive wave painter of exercise 2.49 8 | ; (to add a smile, for example). 9 | 10 | ; b. Change the pattern constructed by corner-split (for example, by 11 | ; using only one copy of the up-split and right-split images instead of 12 | ; two). 13 | 14 | ; c. Modify the version of square-limit that uses square-of-four so as 15 | ; to assemble the corners in a different pattern. (For example, you 16 | ; might make the big Mr. Rogers look outward from each corner of the 17 | ; square.) 18 | ; 19 | ; -------------------------------------------------- 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /2.2/e-2.28.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 2.28. 2 | ; Write a procedure fringe that takes as argument a tree 3 | ; (represented as a list) and returns a list whose elements are 4 | ; all the leaves of the tree arranged in left-to-right order. For example, 5 | 6 | (define x (list (list 1 2) (list 3 4))) 7 | 8 | ; (fringe x) -> (1 2 3 4) 9 | 10 | ; (fringe (list x x)) -> (1 2 3 4 1 2 3 4) 11 | ; ----------------------------------------- 12 | 13 | (load "../common.scm") 14 | (load "../helpers.scm") 15 | 16 | (define (leaf? item) 17 | (not (pair? item))) 18 | 19 | (define (fringe items) 20 | (cond ((null? items) nil) 21 | ((leaf? items) (list items)) 22 | (else (append (fringe (car items)) (fringe (cdr items)))))) 23 | 24 | (output (fringe x)) 25 | (output (fringe (list x x))) 26 | 27 | 28 | -------------------------------------------------------------------------------- /2.1/e-2.7.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 2.7. 2 | ; 3 | ; Alyssa's program is incomplete because she has not specified the implementation 4 | ; of the interval abstraction. Here is a definition of the interval constructor: 5 | 6 | (define (make-interval a b) (cons a b)) 7 | 8 | ; Define selectors upper-bound and lower-bound to complete the implementation. 9 | ; ----------------------------------------------- 10 | 11 | ; loading already given definitions 12 | 13 | (load "2.1.scm") 14 | 15 | ; defining the interval selectors on pairs. 16 | (define (lower-bound x) 17 | (car x)) 18 | 19 | (define (upper-bound x) 20 | (cdr x)) 21 | 22 | ; testing with a few vallues 23 | 24 | (define r1 (make-interval 0.15 0.2)) 25 | (define r2 (make-interval 0.9 1.1)) 26 | 27 | ; (display (lower-bound (add-interval r1 r2))) 28 | ; (newline) 29 | -------------------------------------------------------------------------------- /2.2/e-2.25.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 2.25. 2 | ; Give combinations of cars and cdrs that will pick 3 | ; 7 from each of the following lists: 4 | 5 | ; (1 3 (5 7) 9) 6 | 7 | ; ((7)) 8 | 9 | ; (1 (2 (3 (4 (5 (6 7)))))) 10 | ; ---------------------------- 11 | 12 | (load "../helpers.scm") 13 | 14 | (define first (list 1 3 (list 5 7) 9)) 15 | (define second (list (list 7))) 16 | (define third (list 1 (list 2 (list 3 (list 4 (list 5 (list 6 7))))))) 17 | 18 | ; combinations 19 | (output (car (cdr (car (cdr (cdr first)))))) 20 | (output (car (car second))) 21 | 22 | ; I wrongly assumed that I need just to cdr-down the third definition. 23 | ; (cdr third) -> ((2 (3 (4 (5 (6 7)))))) -> we have to do one car after 24 | ; every cdr 25 | (output (car (cdr (car (cdr (car (cdr (car (cdr (car (cdr (car (cdr third))))))))))))) 26 | 27 | -------------------------------------------------------------------------------- /3.3/e-3.28.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 3.28. 2 | ; 3 | ; Define an or-gate as a primitive function box. Your or-gate 4 | ; constructor should be similar to and-gate. 5 | 6 | (load "../common.scm") 7 | (load "../helpers.scm") 8 | 9 | (define (or-gate a1 a2 output) 10 | (define (or-action-procedure) 11 | (let ((new-value 12 | (logical-or (get-signal a1) (get-signal a2)))) 13 | (after-delay or-gate-delay 14 | (lambda () 15 | (set-signal! output new-value))))) 16 | (add-action! a1 or-action-procedure) 17 | (add-action! a2 or-action-procedure) 18 | 'ok) 19 | 20 | (define (logical-or a b) 21 | (cond ((or (= a 1) (= b 1)) 1) 22 | (else 0))) 23 | 24 | (output (logical-or 1 0)) 25 | (output (logical-or 0 1)) 26 | (output (logical-or 0 0)) 27 | (output (logical-or 1 1)) 28 | -------------------------------------------------------------------------------- /3.5/e-3.79.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 3.79. 2 | ; 3 | ; Generalize the solve-2nd procedure of exercise 3.78 so 4 | ; that it can be used to solve general second-order differential 5 | ; equations d2 y/dt2 = f(dy/dt, y). 6 | ; ------------------------------------------------------------ 7 | 8 | ; to generalize solution for the second order differential equation 9 | ; we have to make the part that produces ddy to be some function and 10 | ; not the concrete sum we had in previous exercise. In the exercise is 11 | ; given function of two params, dy/dt and y so we use generic map 12 | ; function to map the function accross two streams 13 | 14 | (define (solve-2nd dt y0 dy0 f) 15 | (define y (integral (delay dy) y0 dt)) 16 | (define dy (integral (delay ddy) dy0 dt)) 17 | (define ddy (stream-map f dy y)) ; uses generic map zipper 18 | y) 19 | -------------------------------------------------------------------------------- /5.3/notes.md: -------------------------------------------------------------------------------- 1 | # Resource allocation and garbage collection 2 | 3 | Overall it is important to understan that higher level languages operate 4 | on the abstractions that have their own physical representations. Every 5 | time we do (cons x y) it build a new pair that is placed for us 6 | somewhere in the memory. 7 | There isa way objects as lists, procedures and rest are represented in 8 | the physical way, so we can say they are abstractions on top of their 9 | physical representation. 10 | 11 | ## Garbage collection 12 | 13 | Since we use some physical space to store our objects, it is very 14 | important to use that space economicaly since it is not free and 15 | unlimited. Differet strategies are developed to reuse the memory that is 16 | not needed anymore by the certain program, and this concept is called 17 | garbage collection. 18 | -------------------------------------------------------------------------------- /4.1/notes.md: -------------------------------------------------------------------------------- 1 | # Metalinguistic abstraction 2 | 3 | ## Controlling complexity by using appropriate languages 4 | 5 | Previously, we have seen that way to control complexity was building 6 | abstractions by combining primitive elements into more complex ones, 7 | abstracting them and using them further as primitive elements in new, 8 | even higher-level, abstractions. We were using Scheme to build these 9 | abstractions. 10 | 11 | Often, programming language itself is not powerful enough to express all 12 | the abstractions in the domain we are working in. Therefore we have to 13 | create custom language of the domain. This way we can more natively 14 | reason about the problem of the domain and deal with complexity in 15 | simpler way. 16 | 17 | Establishing new languages is called `Metalinguistic abstraction` and is 18 | an ubiquitous way of dealing with complexity. 19 | -------------------------------------------------------------------------------- /3.3/e-3.33.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 3.33. 2 | ; 3 | ; Using primitive multiplier, adder, and constant 4 | ; constraints, define a procedure averager that takes three connectors 5 | ; a, b, and c as inputs and establishes the constraint that the value of 6 | ; c is the average of the values of a and b. 7 | ; ------------------------------------------------------------ 8 | 9 | (load "../helpers.scm") 10 | (load "constraints.scm") 11 | 12 | (define (averager a b c) 13 | (let ((u (make-connector)) 14 | (v (make-connector))) 15 | (adder a b u) 16 | (multiplier c v u) 17 | (constant 2 v))) 18 | 19 | (define a (make-connector)) 20 | (define b (make-connector)) 21 | (define c (make-connector)) 22 | 23 | (averager a b c) 24 | (set-value! a 5 'ivan) 25 | (set-value! b 70 'ivan) 26 | 27 | ; as expected this outputs 37.5 as average for 70 and 5 28 | (output (get-value c)) 29 | -------------------------------------------------------------------------------- /1.1/1.1.scm: -------------------------------------------------------------------------------- 1 | (load "../common.scm") 2 | 3 | (define (abs x) 4 | (cond ((> x 0) x) 5 | ((= x 0) 0) 6 | ((< x 0) (- x)))) 7 | 8 | (define (abs x) 9 | (cond ((< x 0) (- x)) 10 | (else x))) 11 | 12 | (define (abs x) 13 | (if (< x 0) 14 | (- x) 15 | x)) 16 | 17 | (define (>= x y) 18 | (or (> x y) (= x y))) 19 | 20 | 21 | ; Newton square roots finder by iterative guessing 22 | (define (square-iter guess x) 23 | (if (good-enough? guess x) 24 | guess 25 | (square-iter (improve guess x) x))) 26 | 27 | (define (improve guess x) 28 | (average guess (/ x guess))) 29 | 30 | (define (average x y) 31 | (/ (+ x y) 2)) 32 | 33 | (define (square x) 34 | (* x x)) 35 | 36 | (define (good-enough? guess x) 37 | (< (abs (- (square guess) x)) 0.001)) 38 | 39 | (define (sqrt x) 40 | (square-iter 1.0 x)) 41 | 42 | ; (display (sqrt (+ 32 32))) 43 | -------------------------------------------------------------------------------- /5.2/e-5.7.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 5.7. 2 | ; Use the simulator to test the machines you designed in 3 | ; exercise 5.4 4 | ; ------------------------------------------------------------ 5 | (load "5.2.scm") 6 | (load "../helpers.scm") 7 | 8 | (define expt-machine 9 | (make-machine 10 | '(counter base product) 11 | (list (list '- -) (list '* *) (list '= =)) 12 | '(init 13 | (assign counter (const 3)) ; assuming read is a primitive 14 | (assign base (const 5)) 15 | (assign product (const 1)) 16 | expt-iter 17 | (test (op =) (reg counter) (const 0)) 18 | (branch (label expt-done)) 19 | (assign counter (op -) (reg counter) (const 1)) 20 | (assign product (op *) (reg base) (reg product)) 21 | (goto (label expt-iter)) 22 | expt-done))) 23 | 24 | (start expt-machine) 25 | (output (get-register-contents expt-machine 'product)) 26 | -------------------------------------------------------------------------------- /2.3/e-2.72.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 2.72. 2 | ; 3 | ; Consider the encoding procedure that you designed in exercise 4 | ; 2.68. What is the order of growth in the number of steps needed to encode a 5 | ; symbol? Be sure to include the number of steps needed to search the symbol 6 | ; list at each node encountered. To answer this question in general is 7 | ; difficult. Consider the special case where the relative frequencies of the n 8 | ; symbols are as described in exercise 2.71, and give the order of growth (as a 9 | ; function of n) of the number of steps needed to encode the most frequent and 10 | ; least frequent symbols in the alphabet. 11 | ; ------------------------------------------------------------ 12 | 13 | ; Considering in the case of previous that we need O(N) steps to find the lowest element 14 | ; and we need O(n) to search through the list of simbols. We come to the 15 | ; order of growth O(n^2) 16 | 17 | -------------------------------------------------------------------------------- /3.1/e-3.8.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 3.8. 2 | ; 3 | ; When we defined the evaluation model in section 1.1.3, we said 4 | ; that the first step in evaluating an expression is to evaluate its 5 | ; subexpressions. But we never specified the order in which the subexpressions 6 | ; should be evaluated (e.g., left to right or right to left). When we introduce 7 | ; assignment, the order in which the arguments to a procedure are evaluated can 8 | ; make a difference to the result. Define a simple procedure f such that 9 | ; evaluating (+ (f 0) (f 1)) will return 0 if the arguments to + are evaluated 10 | ; from left to right but will return 1 if the arguments are evaluated from 11 | ; right to left. 12 | ; ------------------------------------------------------------ 13 | 14 | ; TODO: I don't want to make a dummy procedure just to satisfy the assignment. 15 | ; That is easy, maybe there is some that exposes the problem more clearly. 16 | -------------------------------------------------------------------------------- /2.2/e-2.48.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 2.48. A directed line segment in the plane can be 2 | ; represented as a pair of vectors -- the vector running from the origin 3 | ; to the start-point of the segment, and the vector running from the 4 | ; origin to the end-point of the segment. Use your vector representation 5 | ; from exercise 2.46 to define a representation for segments with a 6 | ; constructor make-segment and selectors start-segment and end-segment. 7 | ; -------------------------------------------------- 8 | 9 | (load "../helpers.scm") 10 | (load "e-2.46.scm") 11 | 12 | (define (make-segment start end) 13 | (cons start end)) 14 | 15 | (define (start-segment segment) 16 | (car segment)) 17 | 18 | (define (end-segment segment) 19 | (cdr segment)) 20 | 21 | (define test-segment (make-segment (make-vect 0 0) (make-vect 1 1))) 22 | (output (start-segment test-segment)) 23 | (output (end-segment test-segment)) 24 | 25 | -------------------------------------------------------------------------------- /2.2/e-2.40.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 2.40. 2 | ; 3 | ; Define a procedure unique-pairs that, given an integer n, generates the 4 | ; sequence of pairs (i,j) with 1< j< i< n. Use unique-pairs to simplify 5 | ; the definition of prime-sum-pairs given above. 6 | ; ---------------------------------------------- 7 | 8 | (load "../common.scm") 9 | (load "../helpers.scm") 10 | (load "2.2.scm") 11 | 12 | ; defining generator of unique pairs 13 | 14 | (define (unique-pairs n) 15 | (flatmap (lambda (i) 16 | (map (lambda (j) (list i j)) 17 | (enumerate-interval 1 (- i 1)))) 18 | (enumerate-interval 1 n))) 19 | 20 | (output (unique-pairs 10)) 21 | 22 | ; by using this procedure prime sum of pairs looks pretty 23 | ; straightforward 24 | 25 | (define (prime-sum-pairs n) 26 | (map make-pair-sum 27 | (filter prime-sum? 28 | (unique-pairs n)))) 29 | 30 | (output (prime-sum-pairs 10)) 31 | 32 | -------------------------------------------------------------------------------- /2.2/e-2.45.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 2.45. Right-split and up-split can be expressed as instances 2 | ; of a general splitting operation. Define a procedure split with the 3 | ; property that evaluating 4 | 5 | (define right-split (split beside below)) 6 | (define up-split (split below beside)) 7 | 8 | ; produces procedures right-split and up-split with the same behaviors 9 | ; as the ones already defined. 10 | ; ------------------------------------- 11 | 12 | ; So, goal is to define split operation that can accept operations as 13 | ; paramters 14 | 15 | (define (split split-position identity-position) 16 | (lambda (painter) 17 | (identity-position painter (split-position painter painter)))) 18 | 19 | ; if we want to make it recursive 20 | (define (split split-position identity-position) 21 | (lambda (painter n) 22 | (let ((smaller (split painter (- n 1)))) 23 | (identity-position painter (split-position smaller smaller))))) 24 | -------------------------------------------------------------------------------- /4.4/e-4.56.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 4.56. Formulate compound queries that retrieve the following 2 | ; information: 3 | 4 | ; a. the names of all people who are supervised by Ben Bitdiddle, 5 | ; together with their addresses; 6 | 7 | ; b. all people whose salary is less than Ben Bitdiddle's, together with 8 | ; their salary and Ben Bitdiddle's salary; 9 | 10 | ; c. all people who are supervised by someone who is not in the computer 11 | ; division, together with the supervisor's name and job. 12 | ; ------------------------------------------------------------ 13 | 14 | ; a) (and (supervisor (Ben Bitdiddle) ?name) 15 | ; (address ?name ?address) 16 | ; 17 | ; b) (and (salary (Ben Bitdiddle) ?ben-amount) 18 | ; (salary ?name ?amount) 19 | ; (lisp-value < ?amoun ?ben-amount) 20 | ; (address ?name ?address)) 21 | ; 22 | ; c) (and (superviser ?superviser ?name) 23 | ; (not (job ?superviser (computer . ?job)))) 24 | -------------------------------------------------------------------------------- /5.4/e-5.23.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 5.23. 2 | ; Extend the evaluator to handle derived expressions 3 | ; such as cond, let, and so on (section 4.1.2). You may ``cheat'' and 4 | ; assume that the syntax transformers such as cond->if are available as 5 | ; machine operations.28 6 | ; ------------------------------------------------------------ 7 | 8 | ; we have to install the basic operations in the machine during the 9 | ; machine definition. These will be taken from the definition of the 10 | ; metacircular evaluator. 11 | 12 | (list (list 'cond? cond?) 13 | (list 'cond->if cond-if)) 14 | ; to install it in the evaluator dispatcher 15 | eval-dispatch 16 | ... 17 | (test (op cond?) (reg exp)) 18 | (branch (label ev-cond)) 19 | ... 20 | 21 | ; to replace current expression with its substitue based on 22 | ; if and to jump to evaluation of if expression 23 | ev-cond 24 | (assign exp (op cond->if) (reg exp)) 25 | (goto (label ev-if)) 26 | -------------------------------------------------------------------------------- /3.3/e-3.13.scm: -------------------------------------------------------------------------------- 1 | (load "3.3.scm") 2 | 3 | ; Exercise 3.13. Consider the following make-cycle procedure, which 4 | ; uses the last-pair procedure defined in exercise 3.12: 5 | 6 | (define (make-cycle x) 7 | (set-cdr! (last-pair x) x) 8 | x) 9 | 10 | ; Draw a box-and-pointer diagram that shows the structure z created by 11 | 12 | (define z (make-cycle (list 'a 'b 'c))) 13 | 14 | ; What happens if we try to compute (last-pair z)? 15 | ; ------------------------------------------------------------ 16 | 17 | (load "../helpers.scm") 18 | 19 | 20 | ; cycle will make this kind of structure 21 | ; 22 | ; z ---> | a | | -> | b | | -> | c | | -| 23 | ; ^ | 24 | ; |-----------------------------------| 25 | ; 26 | ; 27 | ; So, it will make link from last to first element. 28 | ; 29 | ; This can not return last pair, since it will loop forever, given the 30 | ; condition in (last-pair) procedure 31 | ; 32 | 33 | -------------------------------------------------------------------------------- /1.1/e-1.5.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 1.5 2 | ; Ben Bitdiddle has invented a test to determine whether the interpreter he is faced with is using 3 | ; applicative-order evaluation or normal-order evaluation. He defines the following two procedures: 4 | 5 | ; self referencing procedure that will end up in endless recursion when evaluated. 6 | (define (p) (p)) 7 | 8 | ; test is procedure that has 2 branches based on input x so we can choose if we evaluate the second branch. 9 | (define (test x y) 10 | (if (= x 0) 11 | 0 12 | y)) 13 | 14 | ; then he tests the interpreter with 15 | ; (test 0 (p)) 16 | 17 | ; Normal order evaluation: 18 | ; In this case operand (p) will not be evaluated until it is needed by 19 | ; some primitive operation and thus this will return 0 as result. 20 | ; 21 | ; Applicative order evaluation: 22 | ; In this case operand y will be by default evaluated and then it will 23 | ; end up in recursion since (p) points to itself. 24 | -------------------------------------------------------------------------------- /2.2/e-2.21.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 2.21. 2 | ; The procedure square-list takes a list of numbers as argument and returns 3 | ; a list of the squares of those numbers. 4 | 5 | ; (square-list (list 1 2 3 4)) ; -> (1 4 9 16) 6 | 7 | ; Here are two different definitions of square-list. Complete both of them by filling in the missing expressions: 8 | 9 | ; (define (square-list items) 10 | ; (if (null? items) 11 | ; nil 12 | ; (cons ))) 13 | ; 14 | ; (define (square-list items) 15 | ; (map )) 16 | ;-------------------------------------------------- 17 | 18 | (load "../common.scm") 19 | (load "../helpers.scm") 20 | 21 | (define (square-list items) 22 | (if (null? items) 23 | nil 24 | (cons (square (car items)) 25 | (square-list (cdr items))))) 26 | 27 | (output (square-list (list 1 2 3 4 5))) 28 | 29 | (define (square-list items) 30 | (map square (list 1 2 3 4 5))) 31 | 32 | (output (square-list (list 1 2 3 4 5))) 33 | -------------------------------------------------------------------------------- /2.2/e-2.24.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 2.24. 2 | ; 3 | ; Suppose we evaluate the expression (list 1 (list 2 (list 3 4))). 4 | ; Give the result printed by the interpreter, 5 | ; the corresponding box-and-pointer structure, 6 | ; and the interpretation of this as a tree (as in figure 2.6). 7 | ; ------------------------------------------------------------------ 8 | 9 | (load "../helpers.scm") 10 | 11 | (output (list 1 (list 2 (list 3 4)))) ; > (1 (2 (3 4))) 12 | 13 | ; box-and-pointer representation 14 | ; 15 | ; |·| | -> |·| | -> | · | · | 16 | ; 1 2 3 4 17 | ; 18 | ; cdr of first is pointer to next list in which cdr is pointer to last 19 | ; pair (3 4) 20 | ; 21 | ; Tree representation 22 | ; 23 | ; (1 (2 (3 4))) 24 | ; /\ 25 | ; / \ (2 (3 4)) 26 | ; 1 |\ 27 | ; | \ 28 | ; 2 \ (3 4) 29 | ; |\ 30 | ; | \ 31 | ; 3 4 32 | -------------------------------------------------------------------------------- /2.1/e-2.12.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 2.12. 2 | ; Define a constructor make-center-percent that takes a center and a percentage 3 | ; tolerance and produces the desired interval. You must also define a selector 4 | ; percent that produces the percentage tolerance for a given interval. The center 5 | ; selector is the same as the one shown above. 6 | ;-------------------------------------------------- 7 | ; 8 | ; 9 | (load "2.1.scm") 10 | (load "e-2.7.scm") 11 | 12 | 13 | (define (make-center-percent c p) 14 | (let ((np (/ p 100))) ; define normalized percent 15 | (make-interval 16 | (* c (- 1 np)) 17 | (* c (+ 1 np))))) 18 | 19 | (define (percent i) 20 | (* 100.0 21 | (/ 22 | (- (upper-bound i) (center i)) 23 | (center i)))) 24 | 25 | ; now lets test a bit this 26 | ; (display (percent (make-center-percent 10 10))) ; returns 10 27 | ; (newline) 28 | 29 | ; (display (percent (make-center-width 10 1))) ; returns 10 30 | ; (newline) 31 | -------------------------------------------------------------------------------- /1.3/e-1.38.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 1.38. 2 | ; 3 | ; In 1737, the Swiss mathematician Leonhard Euler published a memoir 4 | ; De Fractionibus Continuis, which included a continued fraction expansion 5 | ; for e - 2, where e is the base of the natural logarithms. In this fraction, 6 | ; the Ni are all 1, and the Di are successively 1, 2, 1, 1, 4, 1, 1, 6, 1, 1, 8, .... 7 | ; Write a program that uses your cont-frac procedure from exercise 1.37 to 8 | ; approximate e, based on Euler's expansion. 9 | 10 | (load "e-1.37.scm") 11 | 12 | (define n-proc 13 | (lambda (i) 1)) 14 | 15 | (define d-proc 16 | (lambda (i) 17 | (cond ((= i 1) 1) 18 | ((= i 2) 2) 19 | (else 20 | (if (> (remainder (- i 2) 3) 0) 21 | 1 22 | (* 2 (+ (/ (- i 2) 3.0) 1))))))) 23 | 24 | 25 | (define e-2 26 | (cont-frac-iter n-proc d-proc 100)) 27 | 28 | ; calculates approximation of e as required 29 | ; (display (+ e-2 2)) 30 | ; (newline) 31 | 32 | -------------------------------------------------------------------------------- /4.2/e-4.25.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 4.25. Suppose that (in ordinary applicative-order Scheme) we define 2 | ; unless as shown above and then define factorial in terms of unless as 3 | 4 | (define (factorial n) 5 | (unless (= n 1) 6 | (* n (factorial (- n 1))) 7 | 1)) 8 | 9 | ; What happens if we attempt to evaluate (factorial 5)? Will our definitions 10 | ; work in a normal-order language? 11 | ; ------------------------------------------------------------ 12 | 13 | ; Applicative-order evaluation means that all the operands are evaluated before 14 | ; operator is applied on their values. 15 | ; In our case that means that second argument evaluation would trigger the infinite recursion 16 | ; and will never come to appllying unless on the operands. 17 | ; 18 | ; In normal order evaluation, only the condition will be evaluated and consequent 19 | ; will be evaluated only after the condition turned out false, when it is true (= n 1) => #t 20 | ; it will finish the recursion. 21 | -------------------------------------------------------------------------------- /5.1/e-5.5.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 5.5. Hand-simulate the factorial and Fibonacci machines, 2 | ; using some nontrivial input (requiring execution of at least one 3 | ; recursive call). Show the contents of the stack at each significant 4 | ; point in the execution. 5 | ; ------------------------------------------------------------ 6 | 7 | ; Lets take the smallest after the trivial cases, n = 3 8 | 9 | ; start 10 | ; n = 3, val = whatever, continue = after-fact 11 | ; stack = empty 12 | ; 13 | ; after 1st loop 14 | ; n = 2, val = whatever 15 | ; stack = 3 | fact-done 16 | ; 17 | ; after 2nd loop 18 | ; n = 1, val = whatever 19 | ; stack = 2 | after-fact | 3 | fact-done 20 | ; 21 | ; after 3rd loop 22 | ; n = 1, val = 1 23 | ; stack = 2 | after-fact | 3 | fact-done 24 | ; 25 | ; jumped to after-fact 26 | ; n = 1, val = 2 27 | ; stack = 3 | fact-done 28 | ; 29 | ; jumped to after-fact 30 | ; n = 1, val = 6 31 | ; stack = empty 32 | ; 33 | ; jumped to fact-done 34 | ; n = 1, val = 6 35 | ; stack = empty 36 | -------------------------------------------------------------------------------- /2.4/e-2.75.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 2.75. Implement the constructor make-from-mag-ang in 2 | ; message-passing style. This procedure should be analogous to the 3 | ; make-from-real-imag procedure given. 4 | ; 5 | ; (define (make-from-real-imag x y) 6 | ; (define (dispatch op) 7 | ; (cond ((eq? op 'real-part) x) 8 | ; ((eq? op 'imag-part) y) 9 | ; ((eq? op 'magnitude) 10 | ; (sqrt (+ (square x) (square y)))) 11 | ; ((eq? op 'angle) (atan y x)) 12 | ; (else 13 | ; (error "Unknown op -- MAKE-FROM-REAL-IMAG" op)))) 14 | ; dispatch) 15 | ; ------------------------------------------------------------ 16 | 17 | (define (make-from-mag-ang r a) 18 | (define (dispatch op) 19 | (cond ((eq? op 'real-part) (* r (cos a))) 20 | ((eq? op 'imag-part) (* r (sin a))) 21 | ((eq? op 'magnitude) r) 22 | ((eq? op 'angle) a) 23 | (else 24 | (eror "Unknown op -- MAKE-FROM-MAG-ANG" op)))) 25 | dispatch) 26 | 27 | 28 | -------------------------------------------------------------------------------- /3.2/e-3.9.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 3.9. 2 | ; 3 | ; In section 1.2.1 we used the substitution model to 4 | ; analyze two procedures for computing factorials, a recursive version 5 | 6 | (define (factorial n) 7 | (if (= n 1) 8 | 1 9 | (* n (factorial (- n 1))))) 10 | 11 | ; and an iterative version 12 | 13 | (define (factorial n) 14 | (fact-iter 1 1 n)) 15 | (define (fact-iter product counter max-count) 16 | (if (> counter max-count) 17 | product 18 | (fact-iter (* counter product) 19 | (+ counter 1) 20 | max-count))) 21 | 22 | ; Show the environment structures created by evaluating (factorial 6) 23 | ; using each version of the factorial procedure.14 24 | ; 25 | ; -------- 26 | ; 27 | ; Solution to this is drawing of the environmental model for both of the 28 | ; executions. There is nothing special to see here except the fact that 29 | ; application of same function will produce new frames every time it is 30 | ; applied to the new arguments. 31 | -------------------------------------------------------------------------------- /2.1/e-2.13.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 2.13. 2 | ; Show that under the assumption of small percentage tolerances there is a 3 | ; simple formula for the approximate percentage tolerance of the product of two 4 | ; intervals in terms of the tolerances of the factors. You may simplify the 5 | ; problem by assuming that all numbers are positive. 6 | ; -------------------------------------------------- 7 | ; 8 | ; If we represent intervals with percentages like this [a*(1 - Pa), a*(1 + Pa)] 9 | ; then multiplication is 10 | ; 11 | ; [a*(1 - Pa), a*(1 + Pa)] * [b*(1 - Pb), b*(1 + Pb)] 12 | ; 13 | ; which at the end comes to 14 | ; 15 | ; [a*b*(1 - (Pa + Pb - Pa*Pb)), a*b*(1 + (Pa + Pb + Pa*Pb))] 16 | ; 17 | ; so in order to set it into wanted form we have to make 18 | ; 19 | ; Pa + Pb - Pa*Pb == Pa + Pb + Pa*Pb 20 | ; 21 | ; If Pa and Pb are really small then their product is becoming 22 | ; insignificant comparing to Pa and Pb and can be discarded as such. 23 | ; 24 | ; So percentage in this case can be expressed as Pa + Pb. 25 | -------------------------------------------------------------------------------- /2.2/e-2.50.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 2.50. 2 | ; 3 | ; Define the transformation flip-horiz, which flips 4 | ; painters horizontally, and transformations that rotate painters 5 | ; counterclockwise by 180 degrees and 270 degrees. 6 | ; -------------------------------------------------- 7 | 8 | ; First to flip horizontally 9 | (define (flip-horiz painter) 10 | (transform-painter painter 11 | (make-vect 1.0 0.0) 12 | (make-vect 0.0 0.0) 13 | (make-vect 1.0 1.0))) 14 | 15 | 16 | ; Counterclockwise 180 17 | (define (rotate-180-cc painter) 18 | (transform-painter painter 19 | (make-vect 1.0 1.0) 20 | (make-vect 1.0 0.0) 21 | (make-vect 0.0 1.0))) 22 | 23 | ; Counterclockwise 270 24 | (define (rotate-270-cc painter) 25 | (transform-painter painter 26 | (make-vect 0.0 1.0) 27 | (make-vect 1.0 1.0) 28 | (make-vect 0.0 0.0))) 29 | 30 | 31 | -------------------------------------------------------------------------------- /3.5/e-3.78.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 3.78. 2 | ; 3 | ; Consider the problem of designing a signal-processing system to study 4 | ; the homogeneous second-order linear differential equation 5 | 6 | ; d^2y/dt^2 - a*dy/dt - by = 0 7 | 8 | ; The output stream, modeling y, is generated by a network that contains 9 | ; a loop. This is because the value of d2y/dt2 depends upon the values 10 | ; of y and dy/dt and both of these are determined by integrating 11 | ; d2y/dt2. The diagram we would like to encode is shown in figure 3.35. 12 | ; Write a procedure solve-2nd that takes as arguments the constants a, 13 | ; b, and dt and the initial values y0 and dy0 for y and dy/dt and 14 | ; generates the stream of successive values of y. 15 | ; ------------------------------------------------------------ 16 | 17 | (define (solve-2nd a b dt y0 dy0) 18 | (define y (integral (delay dy) y0 dt)) 19 | (define dy (integral (delay ddy) dy0 dt)) 20 | (define ddy (add-streams (scale-stream dy a) 21 | (scale-stream y b))) 22 | y) 23 | -------------------------------------------------------------------------------- /3.4/e-3.43.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 3.43. 2 | ; 3 | ; Suppose that the balances in three accounts start out 4 | ; as $10, $20, and $30, and that multiple processes run, exchanging the 5 | ; balances in the accounts. Argue that if the processes are run 6 | ; sequentially, after any number of concurrent exchanges, the account 7 | ; balances should be $10, $20, and $30 in some order. Draw a timing 8 | ; diagram like the one in figure 3.29 to show how this condition can be 9 | ; violated if the exchanges are implemented using the first version of 10 | ; the account-exchange program in this section. On the other hand, argue 11 | ; that even with this exchange program, the sum of the balances in the 12 | ; accounts will be preserved. Draw a timing diagram to show how even 13 | ; this condition would be violated if we did not serialize the 14 | ; transactions on individual accounts. 15 | ; ------------------------------------------------------------ 16 | 17 | ; Essentially reasoning about the permutation of procedure executions 18 | ; and drawing them ... 19 | -------------------------------------------------------------------------------- /5.4/e-5.27.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 5.27. For comparison with exercise 5.26, explore the behavior of 2 | ; the following procedure for computing factorials recursively: 3 | 4 | (define (factorial n) 5 | (if (= n 1) 6 | 1 7 | (* (factorial (- n 1)) n))) 8 | 9 | ; By running this procedure with the monitored stack, determine, as a 10 | ; function of n, the maximum depth of the stack and the total number of 11 | ; pushes used in evaluating n! for n > 1. (Again, these functions will be 12 | ; linear.) Summarize your experiments by filling in the following table with 13 | ; the appropriate expressions in terms of n: 14 | 15 | ; The maximum depth is a measure of the amount of space used by the evaluator 16 | ; in carrying out the computation, and the number of pushes correlates well 17 | ; with the time required. 18 | ; ------------------------------------------------------------ 19 | 20 | ; here the depth grows linearly. This shows that we will need much more space on the stack 21 | ; to calculate the factorial this way. 22 | ; depth = 5*n + 3 23 | -------------------------------------------------------------------------------- /5.4/e-5.29.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 5.29. 2 | ; 3 | ; Monitor the stack operations in the tree-recursive Fibonacci 4 | ; computation: 5 | 6 | (define (fib n) 7 | (if (< n 2) 8 | n 9 | (+ (fib (- n 1)) (fib (- n 2))))) 10 | 11 | ; a. Give a formula in terms of n for the maximum depth of the stack required 12 | ; to compute Fib(n) for n > 2. Hint: In section 1.2.2 we argued that the space 13 | ; used by this process grows linearly with n. 14 | 15 | ; b. Give a formula for the total number of pushes used to compute Fib(n) for n 16 | ; > 2. You should find that the number of pushes (which correlates well with 17 | ; the time used) grows exponentially with n. Hint: Let S(n) be the number of 18 | ; pushes used in computing Fib(n). You should be able to argue that there is a 19 | ; formula that expresses S(n) in terms of S(n - 1), S(n - 2), and some fixed 20 | ; ``overhead'' constant k that is independent of n. Give the formula, and say 21 | ; what k is. Then show that S(n) can be expressed as a Fib(n + 1) + b and give 22 | ; the values of a and b. 23 | -------------------------------------------------------------------------------- /5.5/e-5.36.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 5.36. What order of evaluation does our compiler produce for 2 | ; operands of a combination? Is it left-to-right, right-to-left, or some other 3 | ; order? Where in the compiler is this order determined? Modify the compiler so 4 | ; that it produces some other order of evaluation. (See the discussion of order 5 | ; of evaluation for the explicit-control evaluator in section 5.4.1.) How does 6 | ; changing the order of operand evaluation affect the efficiency of the code 7 | ; that constructs the argument list? 8 | ; ------------------------------------------------------------ 9 | 10 | ; Evaluation is done from right to left, because the way we use argument list is that we 11 | ; cons on top of it the arguments so in order to preserve correct order we do it backwards. 12 | ; It is defined in couple of places. First in way machine uses it, and second in the place where we 13 | ; generate code for computation of the arguments. 14 | ; 15 | ; I guess efficiency depends on the way we write code, as we saw it could be either way. 16 | -------------------------------------------------------------------------------- /1.2/e-1.12.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 1.12. The following pattern of numbers is called Pascal's triangle. 2 | ; 3 | ; rows 4 | ; 1 | 1 5 | ; 2 | 1 1 6 | ; 3 | 1 2 1 7 | ; 4 | 1 3 3 1 8 | ; 5 | 1 4 6 4 1 9 | ; -------------------- 10 | ; cols 1 2 3 4 5 11 | ; The numbers at the edge of the triangle are all 1, and each number inside 12 | ; the triangle is the sum of the two numbers above it. 13 | ; Write a procedure that computes elements of Pascal's triangle by means of a recursive process. 14 | ; 15 | ; ----------------------------------------------------------------- 16 | ; 17 | ; 18 | ; For given row and col 1-based values, we can define this simple 19 | ; recursive function. 20 | 21 | 22 | (define (pascal row col) 23 | (if (or (= col 1) (= col row)) 24 | 1 25 | (+ 26 | (pascal (- row 1) (- col 1)) 27 | (pascal (- row 1) col)))) 28 | 29 | (display (pascal 10 5)) 30 | (newline) 31 | -------------------------------------------------------------------------------- /3.5/e-3.68.scm: -------------------------------------------------------------------------------- 1 | (load "../helpers.scm") 2 | (load "3.5.scm") 3 | 4 | ; Exercise 3.68. 5 | ; 6 | ; Louis Reasoner thinks that building a stream of pairs 7 | ; from three parts is unnecessarily complicated. Instead of separating 8 | ; the pair (S0,T0) from the rest of the pairs in the first row, he 9 | ; proposes to work with the whole first row, as follows: 10 | 11 | (define (pairs s t) 12 | (interleave 13 | (stream-map (lambda (x) (list (stream-car s) x)) 14 | t) 15 | (pairs (stream-cdr s) (stream-cdr t)))) 16 | 17 | ; Does this work? Consider what happens if we evaluate (pairs integers 18 | ; integers) using Louis's definition of pairs. 19 | ; ------------------------------------------------------------ 20 | 21 | ; Example (display-stream-head (pairs integers integers) 20) 22 | ; 23 | ; shows that this ends up in the infinite loop. 24 | ; Problem with this approach is that we are not putting (interleave) 25 | ; in the delayed execution but executing immediatelly which is bringing 26 | ; us to infinite loop within (pairs) procedure. 27 | -------------------------------------------------------------------------------- /4.2/e-4.29.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 4.29. Exhibit a program that you would expect to run much 2 | ; more slowly without memoization than with memoization. Also, consider 3 | ; the following interaction, where the id procedure is defined as in 4 | ; exercise 4.27 and count starts at 0: 5 | 6 | (define (square x) 7 | (* x x)) 8 | ;;; L-Eval input: 9 | (square (id 10)) 10 | ;;; L-Eval value: 11 | 12 | ;;; L-Eval input: 13 | count 14 | ;;; L-Eval value: 15 | 16 | 17 | ; Give the responses both when the evaluator memoizes and when it does 18 | ; not. 19 | 20 | ; ------------------------------------------------------------ 21 | 22 | ; Every program that would have passed argument whose value is result of 23 | ; some intensive computatio and the procudure that uses the argument often 24 | ; would have significant impact on performance without memoization. 25 | 26 | ; If we don't have memoization in this case count would be immediately 2 27 | ; because square would evaluate (id 10) two times for application of the 28 | ; primitive procedure * 29 | -------------------------------------------------------------------------------- /1.3/e-1.30.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 1.30. 2 | ; 3 | ; The sum procedure above generates a linear recursion. 4 | ; The procedure can be rewritten so that the sum is performed iteratively. 5 | ; Show how to do this by filling in the missing expressions in the following definition: 6 | ; 7 | ; (define (sum term a next b) 8 | ; (define (iter a result) 9 | ; (if 10 | ; 11 | ; (iter ))) 12 | ; (iter )) 13 | ; --------------------------------- 14 | 15 | ; One thing to note is that all arguments passed to sum procedure are available 16 | ; in internal iter procedure as well. 17 | 18 | (load "../common.scm") 19 | 20 | (define (sum term a next b) 21 | (define (iter a result) 22 | (if (> a b) 23 | result 24 | (iter (next a) (+ (term a) result)))) 25 | (iter a 0)) 26 | 27 | ; define test function on top of this implementation of sum 28 | 29 | (define (sum-cubes a b) 30 | (define (next x) (+ x 1)) 31 | (sum cube a next b)) 32 | 33 | ; (display (sum-cubes 1 10)) ; expected 3025 34 | ; (newline) 35 | -------------------------------------------------------------------------------- /4.1/e-4.14.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 4.14. 2 | ; 3 | ; Eva Lu Ator and Louis Reasoner are each experimenting with 4 | ; the metacircular evaluator. Eva types in the definition of map, and runs some 5 | ; test programs that use it. They work fine. Louis, in contrast, has installed 6 | ; the system version of map as a primitive for the metacircular evaluator. When 7 | ; he tries it, things go terribly wrong. Explain why Louis's map fails even 8 | ; though Eva's works. 9 | ; ------------------------------------------------------------ 10 | 11 | ; The difference between the two approaches is that when map procedure 12 | ; is defined by definition in REPL it is built as compound procedure and 13 | ; application for compound procedure is called. 14 | ; 15 | ; In the case when map is defined as primitive and executed as apply-primitive, 16 | ; passed function will not be processed and passed to map as implementation of 17 | ; the procedure but will be passed as procedure object which our underlying 18 | ; implementation an't use as parameter in the system defined map procedure. 19 | -------------------------------------------------------------------------------- /3.5/e-3.50.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 3.50. Complete the following definition, which generalizes 2 | ; stream-map to allow procedures that take multiple arguments, analogous to map 3 | ; in section 2.2.3, footnote 12. 4 | 5 | ; (define (stream-map proc . argstreams) 6 | ; (if ( (car argstreams)) 7 | ; the-empty-stream 8 | ; ( 9 | ; (apply proc (map argstreams)) 10 | ; (apply stream-map 11 | ; (cons proc (map argstreams)))))) 12 | ; ------------------------------------------------------------ 13 | 14 | (load "../helpers.scm") 15 | (load "../common.scm") 16 | (load "3.5.scm") 17 | 18 | (define (stream-map proc . argstreams) 19 | (if (stream-null? (car argstreams)) 20 | the-empty-stream 21 | (cons-stream 22 | (apply proc (map car argstreams)) 23 | (apply stream-map 24 | (cons proc (map stream-cdr argstreams)))))) 25 | 26 | (define mapped (stream-map (lambda (x y) (+ x y)) (stream-enumerate-interval 1 10) (stream-enumerate-interval 2 20))) 27 | (output (stream-car (stream-cdr mapped))) 28 | -------------------------------------------------------------------------------- /2.2/e-2.33.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 2.33. 2 | ; 3 | ; Fill in the missing expressions to complete the following definitions of some 4 | ; basic list-manipulation operations as accumulations: 5 | 6 | ; (define (map p sequence) 7 | ; (accumulate (lambda (x y) ) nil sequence)) 8 | ; (define (append seq1 seq2) 9 | ; (accumulate cons )) 10 | ; (define (length sequence) 11 | ; (accumulate 0 sequence)) 12 | ; ---------------------------------------- 13 | 14 | (load "../helpers.scm") 15 | (load "../common.scm") 16 | (load "2.2.scm") 17 | ; Solutions 18 | ; 19 | ; 1. Map 20 | 21 | (define (map p sequence) 22 | (accumulate 23 | (lambda (x y) (cons (p x) y)) 24 | nil 25 | sequence)) 26 | 27 | (output (map square (list 1 2 3 4 5))) 28 | 29 | ; 2. Append 30 | 31 | (define (append seq1 seq2) 32 | (accumulate cons seq2 seq1)) 33 | 34 | 35 | (output (append (list 1 2 3) (list 4 5 6))) 36 | 37 | ; 3. length 38 | 39 | (define (length sequence) 40 | (accumulate (lambda (x y) (+ 1 y)) 0 sequence)) 41 | 42 | (output (length (list 1 4 19 100 3425 100 300))) 43 | -------------------------------------------------------------------------------- /1.1/e-1.8.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 1.8. 2 | ; Newton's method for cube roots is based on the fact that 3 | ; if y is an approximation to the cube root of x, then a better approximation is given by the value 4 | ; (x/y^2 + 2y) / 3 5 | ; Use this formula to implement a cube-root procedure analogous to the square-root procedure. 6 | 7 | (define (square x) (* x x)) 8 | 9 | (define (improve guess x) 10 | (/ 11 | (+ 12 | (/ x (square guess)) 13 | (* guess 2)) 14 | 3)) 15 | 16 | (define (cube-root-iter guess x) 17 | (if (in-delta? guess (improve guess x)) 18 | guess 19 | (begin 20 | (display guess) 21 | (newline) 22 | (cube-root-iter (improve guess x) x)))) 23 | 24 | (define (in-delta? guess1 guess2) 25 | (< (abs (- guess1 guess2)) 0.001)) 26 | 27 | (define (cube-root x) 28 | (cube-root-iter 1.0 x)) 29 | 30 | ; (display (cube-root 8100)) 31 | ; (newline) 32 | 33 | 34 | ; To solve this escercise we just need to replace the way we improve our 35 | ; guess in every new iteration. I renamed the methods so they match the 36 | ; problem we are trying to solve. 37 | -------------------------------------------------------------------------------- /3.1/e-3.1.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 3.1. An accumulator is a procedure that is called repeatedly 2 | ; with a single numeric argument and accumulates its arguments into a 3 | ; sum. Each time it is called, it returns the currently accumulated sum. 4 | ; Write a procedure make-accumulator that generates accumulators, each 5 | ; maintaining an independent sum. The input to make-accumulator should 6 | ; specify the initial value of the sum; for example 7 | 8 | ; (define A (make-accumulator 5)) 9 | ; (A 10) ; 15 10 | ; (A 10) ; 25 11 | ; ------------------------------------------------------------ 12 | 13 | (load "../helpers.scm") 14 | 15 | (define (make-accumulator n) 16 | (let ((accumulated n)) ; initialization of environment with free variable 17 | (lambda (addition) ; producing the "accumulation processor" procedure 18 | (set! accumulated (+ accumulated addition)) 19 | accumulated))) 20 | 21 | ; we create accumulator object that contains local state and one action 22 | ; which is returned autmatically as result 23 | (define A (make-accumulator 5)) 24 | (output (A 10)) ; 15 25 | (output (A 10)) ; 25 26 | -------------------------------------------------------------------------------- /3.5/e-3.57.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 3.57. 2 | ; 3 | ; How many additions are performed when we compute the 4 | ; nth Fibonacci number using the definition of fibs based on the 5 | ; add-streams procedure? Show that the number of additions would be 6 | ; exponentially greater if we had implemented (delay ) simply as 7 | ; (lambda () ), without using the optimization provided by the 8 | ; memo-proc procedure described in section 3.5.1 9 | ; ------------------------------------------------------------ 10 | 11 | ; When we use memoization of the sequence element values, number of additions is n - 1 since for every 12 | ; Nth fibonacci we have to calculate previous n-1, and we do every 13 | ; calculation only once. 14 | ; 15 | ; As it was discussed during examinations of orders of growth regarding 16 | ; the fibonacci sequence, it takes order of growth O(Fib(N)) to 17 | ; calculate it recursivelly without memoization. 18 | ; Somehow differently presented, but the order of growth here is the 19 | ; same since we will have to do all the additions for every Fib sequence 20 | ; element, thus it will grow exponentially. 21 | -------------------------------------------------------------------------------- /5.2/e-5.9.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 5.9. 2 | ; The treatment of machine operations above permits them to 3 | ; operate on labels as well as on constants and the contents of registers. 4 | ; Modify the expression-processing procedures to enforce the condition that 5 | ; operations can be used only with registers and constants. 6 | ; ------------------------------------------------------------ 7 | 8 | ; we have to modify the place where expressions for the operands of 9 | ; the operations are converted to execution procedures and prevent 10 | ; operations on labels. 11 | 12 | ; operation expression 13 | (define (make-operation-exp exp machine labels operations) 14 | (let ((op (lookup-prim (operation-exp-op exp) operations)) 15 | (aprocs 16 | (map (lambda (e) 17 | (if (not (or (register-exp? e) (constant-exp? e))) 18 | (error "This expression is not allowed as operand -- MAKE-OPERATION-EXP" e)) 19 | (make-primitive-exp e machine labels)) 20 | (operation-exp-operands exp)))) 21 | (lambda () 22 | (apply op (map (lambda (p) (p)) aprocs))))) 23 | -------------------------------------------------------------------------------- /2.2/e-2.30.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 2.30. 2 | ; 3 | ; Define a procedure square-tree analogous to the square-list procedure 4 | ; of exercise 2.21. That is, square-list should behave as follows: 5 | 6 | ; (square-tree 7 | ; (list 1 8 | ; (list 2 (list 3 4) 5) 9 | ; (list 6 7))) 10 | 11 | ; (1 (4 (9 16) 25) (36 49)) 12 | 13 | ; Define square-tree both directly (i.e., without using any higher-order procedures) 14 | ; and also by using map and recursion. 15 | ; --------------------------------------------------------------------- 16 | 17 | (define (square-list items) 18 | (if (null? items) 19 | nil 20 | (cons (square (car items)) 21 | (square-list (cdr items))))) 22 | 23 | (load "../common.scm") 24 | (load "../helpers.scm") 25 | 26 | (define (square-tree tree) 27 | (cond ((null? tree) nil) 28 | ((not (pair? tree)) (square tree)) 29 | (else (cons (square-tree (car tree)) 30 | (square-tree (cdr tree)))))) 31 | 32 | 33 | (output (square-tree (list 1 (list 2 (list 3 4) 5) (list 6 7)))) 34 | (output (square-tree (list 5 (list (list 10 20) (list 10 20))))) 35 | -------------------------------------------------------------------------------- /4.1/e-4.10.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 4.10. 2 | ; 3 | ; By using data abstraction, we were able to write an eval 4 | ; procedure that is independent of the particular syntax of the language to be 5 | ; evaluated. To illustrate this, design and implement a new syntax for Scheme 6 | ; by modifying the procedures in this section, without changing eval or apply. 7 | ; ------------------------------------------------------------ 8 | 9 | 10 | ; I won't do implementation but rather explain how to do the change. 11 | ; 12 | ; On one side there is a very direct possibility to do trivial change of the names 13 | ; of the operators. For example changing `or` to `my-or` is ust a matter of 14 | ; updating the predicate for identifying the construct in the evaluator. 15 | ; 16 | ; (define (or? exp) (eq? (car exp) 'my-or?)) 17 | ; 18 | ; How it is abstracted it is even possible to do the non-trivial changes like 19 | ; changing the signature by not affecting the structure of the evaluator. In that 20 | ; case we would have to implement set of function that do evaluation expansion ... 21 | ; but we would not need to change the structure of the evaluator. 22 | -------------------------------------------------------------------------------- /2.2/e-2.27.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 2.27. 2 | ; 3 | ; Modify your reverse procedure of exercise 2.18 4 | ; to produce a deep-reverse procedure that takes a 5 | ; list as argument and returns as its value the list with 6 | ; its elements reversed and with all sublists deep-reversed as well. For example, 7 | 8 | (define x (list (list 1 2) (list 3 4))) 9 | 10 | ; x -> ((1 2) (3 4)) 11 | 12 | ; (reverse x) -> ((3 4) (1 2)) 13 | 14 | ; (deep-reverse x) -> ((4 3) (2 1)) 15 | 16 | (load "../common.scm") 17 | (load "../helpers.scm") 18 | (load "../e-2.18.scm") 19 | 20 | (output (reverse x)) 21 | 22 | ; we can recursevly apply reverse based on check if argument is pair 23 | 24 | (define (deep-reverse items) 25 | (cond ((null? items) nil) 26 | ((not (pair? items)) items) 27 | (else (append (deep-reverse (cdr items)) (list (deep-reverse (car items))))))) 28 | 29 | ; and result is as expected 30 | (output (deep-reverse x)) 31 | 32 | ; lets check a bit more complex task 33 | 34 | (define y (list (list (list 1 2 3) (list 4 5 6)) (list 7 8 9))) 35 | (output (deep-reverse y)) ; -> quite correctly ((9 8 7) ((6 5 4) (3 2 1))) 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /3.5/e-3.64.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 3.64. Write a procedure stream-limit that takes as arguments 2 | ; a stream and a number (the tolerance). It should examine the stream 3 | ; until it finds two successive elements that differ in absolute value 4 | ; by less than the tolerance, and return the second of the two elements. 5 | ; Using this, we could compute square roots up to a given tolerance by 6 | 7 | ; (define (sqrt x tolerance) 8 | ; (stream-limit (sqrt-stream x) tolerance)) 9 | 10 | ; ------------------------------------------------------------ 11 | 12 | (load "../helpers.scm") 13 | (load "3.5.scm") 14 | 15 | (define (stream-limit stream tolerance) 16 | (let ((first (stream-ref stream 0)) 17 | (second (stream-ref stream 1))) 18 | (if (< (abs (- second first)) tolerance) 19 | second 20 | (stream-limit (stream-cdr stream) tolerance)))) 21 | 22 | (define (sqrt x tolerance) 23 | (stream-limit (sqrt-stream x) tolerance)) 24 | 25 | ; these will all provide result with different precision 26 | (output (sqrt 10 0.1)) ; 3.16245562280389 27 | (output (sqrt 10 0.01)) ; 3.16227766517567 28 | (output (sqrt 10 0.00001)) ; 3.16227766016838 29 | -------------------------------------------------------------------------------- /2.2/e-2.23.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 2.23. 2 | ; The procedure for-each is similar to map. It takes as arguments a procedure and a list of 3 | ; elements. However, rather than forming a list of the results, for-each just applies the 4 | ; procedure to each of the elements in turn, from left to right. The values returned by applying 5 | ; the procedure to the elements are not used at all -- for-each is used with 6 | ; procedures that perform an action, such as printing. For example, 7 | 8 | ; (for-each (lambda (x) (newline) (display x)) 9 | ; (list 57 321 88)) 10 | ; 57 11 | ; 321 12 | ; 88 13 | 14 | ; The value returned by the call to for-each (not illustrated above) can 15 | ; be something arbitrary, such as true. Give an implementation of for-each. 16 | ; -------------------------------------------------------------------- 17 | 18 | (load "../common.scm") 19 | 20 | ; One implementation of for-each can be this 21 | (define (for-each proc items) 22 | (if (null? items) 23 | nil 24 | (begin 25 | (proc (car items)) 26 | (for-each proc (cdr items))))) 27 | 28 | (for-each (lambda (x) (newline) (display x)) 29 | (list 57 321 88)) 30 | -------------------------------------------------------------------------------- /3.3/e-3.34.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 3.34. 2 | ; 3 | ; Louis Reasoner wants to build a squarer, a constraint 4 | ; device with two terminals such that the value of connector b on the 5 | ; second terminal will always be the square of the value a on the first 6 | ; terminal. He proposes the following simple device made from a 7 | ; multiplier: 8 | 9 | ; (define (squarer a b) 10 | ; (multiplier a a b)) 11 | 12 | ; There is a serious flaw in this idea. Explain. 13 | ; ------------------------------------------------------------ 14 | 15 | (load "../helpers.scm") 16 | (load "constraints.scm") 17 | 18 | (define (squarer a b) 19 | (multiplier a a b)) 20 | 21 | (define a (make-connector)) 22 | (define b (make-connector)) 23 | (squarer a b) 24 | 25 | ; Here is easy to see that there is a problem with this constraint. 26 | ; Because of the way multiplier is implemented, we can not set the 27 | ; square value and get the value of squared quantities. It works only in 28 | ; the direction of setting the quantity to be squared and then reading 29 | ; the result 30 | (set-value! b 100 'ivan) 31 | (output (get-value b)) 32 | (output (get-value a)) ; outputs #f which is wrong 33 | -------------------------------------------------------------------------------- /2.5/notes.md: -------------------------------------------------------------------------------- 1 | # Systems with generic operations 2 | 3 | In previous chapter we have introduced the way to abstract the 4 | differences in representation of two data abstractions that represent 5 | the same thing. We introduced the notion of encapsulating knowledge 6 | about relations between related data abstractions. 7 | 8 | Here, we bring this idea to a broader level. Previously we had different 9 | representations of complex numbers involved, now we go one abstraction 10 | up and we make generic arithmetic which works with numbers in general. 11 | 12 | # Coercion 13 | 14 | After we have developed basic generic arithmetic system we see that 15 | there are lot of flaws in the way it works. There are lot of 16 | presumptions to be taken into account in order to use it. One of them is 17 | that we can not sum complex with rationale numbers. We can install all 18 | combination of procedures into all the packages to handle these cases 19 | but there is a better way to do it. It is called coercion. 20 | 21 | # Hierarchies of types 22 | 23 | Coercion is a way to solve conversions between types that have natural 24 | relations. Often there are more complex ways types relate. 25 | -------------------------------------------------------------------------------- /3.3/e-3.37.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 3.37. 2 | ; 3 | ; The celsius-fahrenheit-converter procedure is cumbersome when 4 | ; compared with a more expression-oriented style of definition, such as 5 | 6 | (define (celsius-fahrenheit-converter x) 7 | (c+ (c* (c/ (cv 9) (cv 5)) 8 | x) 9 | (cv 32))) 10 | 11 | (define C (make-connector)) 12 | (define F (celsius-fahrenheit-converter C)) 13 | 14 | ; Here c+, c*, etc. are the ``constraint'' versions of the arithmetic 15 | ; operations. For example, c+ takes two connectors as arguments and returns a 16 | ; connector that is related to these by an adder constraint: 17 | 18 | (define (c+ x y) 19 | (let ((z (make-connector))) 20 | (adder x y z) 21 | z)) 22 | 23 | ; Define analogous procedures c-, c*, c/, and cv (constant value) that enable 24 | ; us to define compound constraints as in the converter example above.33 25 | 26 | (define (c* x y) 27 | (let ((z (make-connector))) 28 | (multiplier x y z) 29 | z)) 30 | 31 | (define (c/ x y z) 32 | (let ((z (make-connection))) 33 | (multiplier y z x) 34 | z)) 35 | 36 | (define (cv x) 37 | (let ((z (make-connection))) 38 | (constant x z) 39 | z)) 40 | -------------------------------------------------------------------------------- /1.3/e-1.43.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 1.43. 2 | ; 3 | ; If f is a numerical function and n is a positive integer, then we can form 4 | ; the nth repeated application of f, which is defined to be the function whose 5 | ; value at x is f(f(...(f(x))...)). For example, if f is the function x -> x + 1, 6 | ; then the nth repeated application of f is the function x -> x + n. If f is the 7 | ; operation of squaring a number, then the nth repeated application of f is the function 8 | ; that raises its argument to the 2nth power. Write a procedure that takes as inputs a 9 | ; procedure that computes f and a positive integer n and returns the procedure that 10 | ; computes the nth repeated application of f. Your procedure should be able to be used as follows: 11 | ; 12 | ; ((repeated square 2) 5) and to produce 625 as result 13 | 14 | (load "../common.scm") 15 | 16 | ; Implementation of repeated application in linearly iterative fashion 17 | (define (repeated f n) 18 | (lambda (x) 19 | (define (iter i result) 20 | (if (= i n) 21 | result 22 | (iter (inc i) (f result)))) 23 | (iter 1 (f x)))) 24 | 25 | 26 | ; (display ((repeated square 2) 5)) ; gives result 625 as expected 27 | ; (newline) 28 | 29 | -------------------------------------------------------------------------------- /3.5/e-3.61.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 3.61. Let S be a power series (exercise 3.59) whose constant 2 | ; term is 1. Suppose we want to find the power series 1/S, that is, the 3 | ; series X such that S · X = 1. Write S = 1 + SR where SR is the part of 4 | ; S after the constant term. Then we can solve for X as follows: 5 | ; 6 | ; S*X = 1 7 | ; (1 + Sr)*X = 1 8 | ; X + Sr*X = 1 9 | ; 10 | ; therefore => X = 1 + Sr*X 11 | ; 12 | ; 13 | ; In other words, X is the power series whose constant term is 1 and 14 | ; whose higher-order terms are given by the negative of SR times X. Use 15 | ; this idea to write a procedure invert-unit-series that computes 1/S 16 | ; for a power series S with constant term 1. You will need to use 17 | ; mul-series from exercise 3.60. 18 | ; ------------------------------------------------------------ 19 | 20 | ; Having already developed basic series and streams manipulation 21 | ; procedures, we can write it like this. 22 | 23 | (load "../helpers.scm") 24 | (load "3.5.scm") 25 | 26 | (define (invert-unit-series stream) 27 | (cons-stream 1 28 | (negate-series (mul-series (stream-cdr stream) 29 | (invert-unit-series stream))))) 30 | -------------------------------------------------------------------------------- /4.1/e-4.11.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 4.11. 2 | ; 3 | ; Instead of representing a frame as a pair of lists, we 4 | ; can represent a frame as a list of bindings, where each binding is a 5 | ; name-value pair. Rewrite the environment operations to use this 6 | ; alternative representation. 7 | ; ------------------------------------------------------------ 8 | 9 | ; Since frame implementation is abstracted, we have to reiplement the 10 | ; abstarction with different underlying implementation 11 | 12 | (load "../helpers.scm") 13 | 14 | (define (make-frame variables values) 15 | (zip-lists cons variables values)) 16 | (define (frame-variables frame) (map car frame)) 17 | (define (frame-values frame) (map cdr frame)) 18 | (define (add-binding-to-frame! var val frame) 19 | (cons frame (cons var val))) 20 | 21 | (define (zip-lists proc . arglists) 22 | (if (null? (car arglists)) 23 | '() 24 | (cons 25 | (apply proc (map car arglists)) 26 | (apply zip-lists 27 | (cons proc (map cdr arglists)))))) 28 | 29 | ;(output (zip-lists cons (list 1 2 3) (list 2 3 4))) 30 | ;(output (map car (zip-lists cons (list 1 2 3) (list 2 3 4)))) 31 | ;(output (map cdr (zip-lists cons (list 1 2 3) (list 2 3 4)))) 32 | -------------------------------------------------------------------------------- /4.1/e-4.13.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 4.13. 2 | ; 3 | ; Scheme allows us to create new bindings for variables by 4 | ; means of define, but provides no way to get rid of bindings. Implement for 5 | ; the evaluator a special form make-unbound! that removes the binding of a 6 | ; given symbol from the environment in which the make-unbound! expression is 7 | ; evaluated. This problem is not completely specified. For example, should we 8 | ; remove only the binding in the first frame of the environment? Complete the 9 | ; specification and justify any choices you make. 10 | ; ------------------------------------------------------------ 11 | 12 | (load "e-4.12.scm") 13 | 14 | ; Using the generic environment traversing functions we can implement easily imlement 15 | ; this operation. 16 | 17 | ; if there is var found in the first frame of the environment 18 | ; we will just relink lists 19 | (define (make-unbound! var env) 20 | (define (found-action vars vals) 21 | (set-car! vars '()) 22 | (set-car! vals '())) 23 | (env-traverse-and-find var found-action '() env)) 24 | 25 | ;(define global-env (list (cons (list 'x 'y) (list 1 2)))) 26 | ;(output global-env) 27 | ;(make-unbound! 'y global-env) 28 | ;(output global-env) 29 | 30 | -------------------------------------------------------------------------------- /2.1/e-2.15.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 2.15. 2 | ; 3 | ; Eva Lu Ator, another user, has also noticed the different intervals computed by different but algebraically 4 | ; equivalent expressions. She says that a formula to compute with intervals using Alyssa's system will produce 5 | ; tighter error bounds if it can be written in such a form that no variable that represents an uncertain number 6 | ; is repeated. Thus, she says, par2 is a ``better'' program for parallel resistances than par1. Is she right? Why? 7 | ; -------------------------------------------- 8 | ; 9 | ; For reference to this explanation look at the previous exercise and 10 | ; results of running it. 11 | ; 12 | ; I suppose she is right since second version produces result which has 13 | ; smaller uncertainity width. Not getting into mathematical explanations 14 | ; of the reasons I think that every arithmetic operation, especially 15 | ; multiplications, will introduce error accumulation and thus as 16 | ; complexity of the equation grows I would expect that precision falls 17 | ; down even when expressions are mathematicaly equivalent. 18 | ; 19 | ; I'm not sure about the number repeating in the equation but I suppose 20 | ; it is part of the "equation complexity" reason? 21 | -------------------------------------------------------------------------------- /3.5/e-3.63.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 3.63. 2 | ; 3 | ; Louis Reasoner asks why the sqrt-stream procedure was 4 | ; not written in the following more straightforward way, without the 5 | ; local variable guesses: 6 | 7 | (define (sqrt-stream x) 8 | (cons-stream 1.0 9 | (stream-map (lambda (guess) 10 | (sqrt-improve guess x)) 11 | (sqrt-stream x)))) 12 | 13 | ; Alyssa P. Hacker replies that this version of the procedure is 14 | ; considerably less efficient because it performs redundant computation. 15 | ; Explain Alyssa's answer. Would the two versions still differ in 16 | ; efficiency if our implementation of delay used only (lambda () ) 17 | ; without using the optimization provided by memo-proc (section 3.5.1)? 18 | ; ------------------------------------------------------------ 19 | 20 | ; In this approach, every call to (sqrt-stream x) will produce new 21 | ; stream. 22 | ; 23 | ; In the example with local variable, we are building stream once, 24 | ; passing it to variable and then reusing this variable when accessing 25 | ; the elements of the stream. 26 | ; 27 | ; I guess it would be similar inefficiency with the non-memo 28 | ; implementation of delay. 29 | -------------------------------------------------------------------------------- /3.4/e-3.44.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 3.44. Consider the problem of transferring an amount from 2 | ; one account to another. Ben Bitdiddle claims that this can be 3 | ; accomplished with the following procedure, even if there are multiple 4 | ; people concurrently transferring money among multiple accounts, using 5 | ; any account mechanism that serializes deposit and withdrawal 6 | ; transactions, for example, the version of make-account in the text 7 | ; above. 8 | 9 | (define (transfer from-account to-account amount) 10 | ((from-account 'withdraw) amount) 11 | ((to-account 'deposit) amount)) 12 | 13 | ; Louis Reasoner claims that there is a problem here, and that we need 14 | ; to use a more sophisticated method, such as the one required for 15 | ; dealing with the exchange problem. Is Louis right? If not, what is the 16 | ; essential difference between the transfer problem and the exchange 17 | ; problem? (You should assume that the balance in from-account is at 18 | ; least amount.) 19 | ; ------------------------------------------------------------ 20 | 21 | ; Here, we don't have intermediate state `difference` that can be affected 22 | ; by the changes in the balances. Withdraw and deposit are synchronized 23 | ; and can't go wrong in this case. 24 | -------------------------------------------------------------------------------- /2.2/e-2.32.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 2.32. 2 | ; 3 | ; We can represent a set as a list of distinct elements, and we can 4 | ; represent the set of all subsets of the set as a list of lists. 5 | ; For example, if the set is (1 2 3), then the set of all subsets is 6 | ; (() (3) (2) (2 3) (1) (1 3) (1 2) (1 2 3)). Complete the following 7 | ; definition of a procedure that generates the set of subsets of a set 8 | ; and give a clear explanation of why it works: 9 | 10 | (load "../helpers.scm") 11 | (load "../common.scm") 12 | 13 | (define (subsets s) 14 | (if (null? s) 15 | (list nil) 16 | (let ((rest (subsets (cdr s)))) 17 | (append rest (map (lambda (x) (cons (car s) x)) rest))))) 18 | 19 | ; gives expected result (() (3) (2) (2 3) (1) (1 3) (1 2) (1 2 3)) 20 | (output (subsets (list 1 2 3))) 21 | 22 | ; The recursive algorithm that is implemented here can be explained in 23 | ; following way suitable for recursive implementation: 24 | ; 25 | ; To list all the subsets of the definite set you need 26 | ; 1. All the subsets of a given set without a certain element 27 | ; 2. You have to add to this all the subsets from point 1 28 | ; but with that element added to the sets. 29 | ; 30 | ; More on this is written: http://en.wikipedia.org/wiki/Power_set#Algorithms 31 | -------------------------------------------------------------------------------- /4.4/e-4.57.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 4.57. Define a rule that says that person 1 can replace 2 | ; person 2 if either person 1 does the same job as person 2 or someone 3 | ; who does person 1's job can also do person 2's job, and if person 1 4 | ; and person 2 are not the same person. Using your rule, give queries 5 | ; that find the following: 6 | 7 | ; a. all people who can replace Cy D. Fect; 8 | 9 | ; b. all people who can replace someone who is being paid more than 10 | ; they are, together with the two salaries. 11 | ; ------------------------------------------------------------ 12 | 13 | (rule (can-replace ?person-1 ?person-2) 14 | (and 15 | (or 16 | (and (job ?person-1 ?person-1-job) 17 | (job ?person-2 ?person-1-job)) 18 | (and (job ?person-1 ?person-1-job) 19 | (job ?person-2 ?person-2-job) 20 | (can-do-job ?person-2-job ?person-1-job))) 21 | (lisp-value neq? ?person-2-name ?person-1-name))) 22 | 23 | 24 | ; a) (can-replace (Cy D. Fect) ?replacment) 25 | ; 26 | ; b) (and 27 | ; (can-replace ?someone ?replacement) 28 | ; (salary ?someone ?someone-salary) 29 | ; (salary ?replacement ?replacement-salary) 30 | ; (lisp-value > ?someone-salary ?replacement-salary)) 31 | -------------------------------------------------------------------------------- /3.4/e-3.40.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 3.40. Give all possible values of x that can result from 2 | ; executing 3 | 4 | (define x 10) 5 | 6 | (parallel-execute (lambda () (set! x (* x x))) 7 | (lambda () (set! x (* x x x)))) 8 | 9 | ; Which of these possibilities remain if we instead use serialized 10 | ; procedures: 11 | 12 | (define x 10) 13 | 14 | (define s (make-serializer)) 15 | 16 | (parallel-execute (s (lambda () (set! x (* x x)))) 17 | (s (lambda () (set! x (* x x x))))) 18 | 19 | ; ------------------------------------------------------------ 20 | 21 | ; There are 7 different cases that can happen and 5 different values to 22 | ; be produced 23 | ; 24 | ; 1) 1.000.000: P1 sets X to 100, P2 sets X to 1.000.000 25 | ; 2) 1.000.000: P2 sets X to 1.000, P1 reads both X and set it to 1.000.000 26 | ; 3) 100.000: P2 reads one X, P1 sets X to 100, P2 sets it to 100.000 27 | ; 4) 10.000: P1 reads X once, P2 sets it to 1000, P1 sets to 10.000 28 | ; 5) 10.000: P2 reads two X, P1 sets X to 100, P2 sets X to 10.000 29 | ; 6) 1.000 P2 reads 3 X, P1 sets X o 100, P2 sets X to 1.000 30 | ; 7) 100: P1 reads both X, P2 sets X to 1.000, P1 sets it to 100 31 | 32 | ; with serialization we can have only (10^3)^2 or ((10^2)^3) which both 33 | ; give 1.000.000 34 | -------------------------------------------------------------------------------- /1.3/e-1.44.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 1.44. 2 | ; 3 | ; The idea of smoothing a function is an important concept in signal processing. 4 | ; If f is a function and dx is some small number, then the smoothed version of f 5 | ; is the function whose value at a point x is the average of f(x - dx), f(x), and f(x + dx). 6 | ; 7 | ; Write a procedure smooth that takes as input a procedure that computes f and returns a procedure that 8 | ; computes the smoothed f. It is sometimes valuable to repeatedly smooth a function (that is, smooth the 9 | ; smoothed function, and so on) to obtained the n-fold smoothed function. 10 | ; Show how to generate the n-fold smoothed function of any given function using smooth and repeated from exercise 1.43. 11 | ; 12 | ; ------------------------------------------------ 13 | ; 14 | 15 | (load "../common.scm") 16 | (load "e-1.43.scm") 17 | 18 | (define dx 0.001) 19 | 20 | (define (smooth f) 21 | (lambda (x) 22 | (average-of-3 (f (- x dx)) (f x) (f (+ x dx))))) 23 | 24 | ; (display ((smooth square) 2)) 25 | ; (newline) 26 | 27 | ; now we repeat smoothing n times by reusing the 28 | ; repeat function and smooth defined above 29 | (define (n-fold-smooth f n) 30 | ((repeated smooth n) f)) 31 | 32 | (display ((n-fold-smooth square 2) 2)) ; and it returns 33 | (newline) 34 | 35 | -------------------------------------------------------------------------------- /1.2/e-1.9.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 1.9. Each of the following two procedures defines a method for adding two 2 | ; positive integers in terms of the procedures inc, which increments its argument by 1, 3 | ; and dec, which decrements its argument by 1. 4 | 5 | ; Definition 1: 6 | ; (define (+ a b) 7 | ; (if (= a 0) 8 | ; b 9 | ; (inc (+ (dec a) b)))) 10 | 11 | ; Definition 2: 12 | ; (define (+ a b) 13 | ; (if (= a 0) 14 | ; b 15 | ; (+ (dec a) (inc b)))) 16 | 17 | ; Using the substitution model, illustrate the process generated by each procedure in evaluating (+ 4 5). Are these processes iterative or recursive? 18 | ; 19 | ; ----------------------------------------------------------- 20 | ; 21 | ; Definition 1 expanded by the applicative substitution model 22 | ; 23 | ; (+ 4 5) 24 | ; (inc (+ 3 5)) 25 | ; (inc (inc (+ 2 5))) 26 | ; (inc (inc (inc (+ 1 5)))) 27 | ; (inc (inc (inc (inc (+ 0 5))))) 28 | ; (inc (inc (inc (inc 5)))) 29 | ; (inc (inc (inc 6))) 30 | ; (inc (inc 7)) 31 | ; (inc 8) 32 | ; 9 33 | ; 34 | ; We clearly see by the shape of the process that it is linear 35 | ; recursive process 36 | ; 37 | ;Definition 2 is expanded like this 38 | ; 39 | ;(+ 4 5) 40 | ;(+ 3 6) 41 | ;(+ 2 7) 42 | ;(+ 1 8) 43 | ;(+ 0 9) 44 | ;9 45 | ; 46 | ; Obviously, it is linear iteration in place here. 47 | -------------------------------------------------------------------------------- /2.2/e-2.18.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 2.18. 2 | ; Define a procedure reverse that takes a list as argument and returns a list of the same elements in reverse order: 3 | ; 4 | ; Example: (reverse (list 1 4 9 16 25)) -> (25 16 9 4 1) 5 | ; ---------------------------------------------------- 6 | 7 | (load "../helpers.scm") 8 | (load "../common.scm") 9 | 10 | ; For me, this would be the natural way of doing it 11 | ; but the way cons work doesn't actually allow this to be represented in 12 | ; some nice way. 13 | (define (reverse items) 14 | (if (null? (cdr items)) 15 | (car items) 16 | (cons (reverse (cdr items)) (car items)))) 17 | 18 | (output (reverse (list 1 2 3 4))) ; -> (((4 . 3) . 2) . 1) 19 | 20 | ; If we want proper representation of the list we have to 21 | ; use helper method append and work with the lists 22 | (define (reverse items) 23 | (if (null? (cdr items)) 24 | (list (car items)) 25 | (append (reverse (cdr items)) (list (car items))))) 26 | 27 | (output (reverse (list 1 4 9 16 25))) ; -> (25 16 9 4 1) 28 | 29 | ; at the end it can be done a bit simpler but with one more recursion 30 | ; call 31 | (define (reverse items) 32 | (if (null? items) 33 | nil 34 | (append (reverse (cdr items)) (list (car items))))) 35 | 36 | (output (reverse (list 1 4 9 16 25))) ; -> (25 16 9 4 1) 37 | -------------------------------------------------------------------------------- /2.5/e-2.80.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 2.80. 2 | ; 3 | ; Define a generic predicate =zero? that tests if its argument 4 | ; is zero, and install it in the generic arithmetic package. This operation 5 | ; should work for ordinary numbers, rational numbers, and complex numbers. 6 | ; ------------------------------------------------------------ 7 | 8 | (load "2.5.scm") 9 | (load "e-2.78.scm") ; to use normal scheme numbers instead of typed 10 | ; Similar to the previous taks, now we just have operation on one operand. 11 | 12 | (define (=zero? x) (apply-generic '=zero? x)) 13 | 14 | ; and to update packages 15 | (define (update-scheme-number-package) 16 | (put '=zero? '(scheme-number) (lambda (x) (= 0 x)))) 17 | 18 | (update-scheme-number-package) 19 | 20 | ; this needs access to internal procedures of the package which is 21 | ; different story 22 | (define (update-rational-package) 23 | (put '=zero? '(rational) 24 | (lambda (x) (= 0 (car x))))) 25 | 26 | (update-rational-package) 27 | 28 | (define (update-complex-package) 29 | (put '=zero? '(complex) 30 | (lambda (c1) (and (= 0 (real-part c1)) (= 0 (imag-part c1)))))) 31 | 32 | (update-complex-package) 33 | 34 | 35 | ; and some tests 36 | 37 | (output (=zero? 0)) 38 | (output (=zero? (make-rational 0 5))) 39 | (output (=zero? (make-complex-from-real-imag 0 0))) 40 | -------------------------------------------------------------------------------- /4.2/notes.md: -------------------------------------------------------------------------------- 1 | # Normal order evaluation (lazy evaluator) 2 | 3 | Interpreter with lazy evaluation (normal-order evaluation) is the one that 4 | does not evaluate operands of the compound procedure during the procedure 5 | application. Instead, the interpreter creates so called `thunks` that 6 | enclose the possibility to `force` the evaluation of its content when 7 | needed. 8 | Evaluation of thunks is done upon application of the primitive 9 | procedure, evaluation of the conditions or if thunk holds the value of 10 | operator to be applied to other operands. 11 | 12 | ## Side effects considerations 13 | 14 | When normal-order evaluation is used, it is important to understand how 15 | it affects the eventual state changes if code that changes state is 16 | passed as argument. In applicative-order evaluation the evaluation of 17 | arguments will change state every time porcedure is called. In 18 | normal-order evaluation, state will be changed only when actual value 19 | is computed. And with memoizatin in place it will take in fact only 20 | once. 21 | 22 | ## Performance considerations. 23 | 24 | Without memoization of the thunk vlaues, every time thunk is used it 25 | will cause evaluation of the actual value of the thunk. If this is 26 | complicated proces it will have performance impact on overall program 27 | execution. 28 | -------------------------------------------------------------------------------- /2.1/e-2.10.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 2.10. 2 | ; 3 | ; Ben Bitdiddle, an expert systems programmer, looks over Alyssa's shoulder and 4 | ; comments that it is not clear what it means to divide by an interval that spans zero. 5 | ; Modify Alyssa's code to check for this condition and to signal an error if it occurs. 6 | ; ---------------------------------------------- 7 | 8 | ; original method of division is 9 | 10 | (load "2.1.scm") 11 | (load "e-2.7.scm") 12 | 13 | (define (div-interval x y) 14 | (mul-interval 15 | x 16 | (make-interval (/ 1.0 (lower-bound y)) 17 | (/ 1.0 (upper-bound y))))) 18 | 19 | ; We can introduce check if interval spans zero by checking if 20 | ; product of lower and upper bound is negative, which would mean that they 21 | ; are from the other sides of the 0 value 22 | 23 | (define (div-interval x y) 24 | (if (< (* (lower-bound y) 25 | (upper-bound y)) 26 | 0) 27 | (error "y is spanning zero") 28 | (mul-interval 29 | x 30 | (make-interval (/ 1.0 (lower-bound y)) 31 | (/ 1.0 (upper-bound y)))))) 32 | 33 | ; can check this with the test 34 | 35 | (div-interval (make-interval 1 2) (make-interval -1 -2)) ; should be OK 36 | (div-interval (make-interval 1 2) (make-interval -1 2)) ; should throw an error, and it throws it!!! yay 37 | -------------------------------------------------------------------------------- /1.2/e-1.17.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 1.17. 2 | ; 3 | ; The exponentiation algorithms in this section are based on 4 | ; performing exponentiation by means of repeated multiplication. 5 | ; In a similar way, one can perform integer multiplication by means of repeated addition. 6 | ; The following multiplication procedure (in which it is assumed that our language can only add, not multiply) 7 | ; is analogous to the expt procedure: 8 | 9 | ; (define (* a b) 10 | ; (if (= b 0) 11 | ; 0 12 | ; (+ a (* a (- b 1))))) 13 | 14 | ; This algorithm takes a number of steps that is linear in b. 15 | ; Now suppose we include, together with addition, operations double, 16 | ; which doubles an integer, and halve, which divides an (even) integer by 2. 17 | ; Using these, design a multiplication procedure analogous to 18 | ; fast-expt that uses a logarithmic number of steps. 19 | 20 | ; -------------------------------- 21 | ; First we define needed auxillary procedures 22 | 23 | (load "../common.scm") 24 | 25 | ; Recursive procedure which halves the problem size in every new call have 26 | ; logarithmic order of growth 27 | 28 | (define (fast-mult a b) 29 | (cond ((= b 0) 0) 30 | ((even? b) (double (fast-mult a (halve b)))) 31 | (else (+ a (fast-mult a (- b 1)))))) 32 | 33 | (display (fast-mult 220000 38000003)) 34 | (newline) 35 | 36 | 37 | -------------------------------------------------------------------------------- /3.3/e-3.29.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 3.29. 2 | ; 3 | ; Another way to construct an or-gate is as a compound digital 4 | ; logic device, built from and-gates and inverters. Define a procedure or-gate 5 | ; that accomplishes this. What is the delay time of the or-gate in terms of 6 | ; and-gate-delay and inverter-delay? 7 | ; --------------------------------------- 8 | 9 | ; Subtitution circuit for OR gate, made of AND and NOT gates can be see here: 10 | ; http://www.kpsec.freeuk.com/gates.htm#substituting 11 | ; I'm treating NAND as sequene of AND gate and inverter. 12 | ; NAND could be defined as separate element for the easier implementation but is not 13 | ; the most important thing here 14 | ; 15 | ; we can define it like this just by reusing already given definitions 16 | 17 | (load "digital_circuit_simulator.scm") 18 | 19 | (define (or-gate a b output) 20 | (let ((c (make-wire)) 21 | (d (make-wire)) 22 | (e (make-wire)) 23 | (f (make-wire)) 24 | (g (make-wire))) 25 | (and-gate a a c) 26 | (and-gate b b d) 27 | (inverter c e) 28 | (inverter d f) 29 | (and-gate e f g) 30 | (inverter g output))) 31 | 32 | ; The way I consider it (NAND as sequence of AND and NOT) the delay 33 | ; is sum of 2 AND circuits and 2 NOT circuits because every change of the 34 | ; signal has to pass through these 4 elements 35 | -------------------------------------------------------------------------------- /2.2/e-2.34.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 2.34. 2 | ; 3 | ; Evaluating a polynomial in x at a given value of x can be 4 | ; formulated as an accumulation. We evaluate the polynomial 5 | ; 6 | ; An*x^n + An-1*x^n-1 + ... + A0 7 | ; 8 | ; using a well-known algorithm called Horner's rule, which structures the computation as 9 | ; 10 | ; (...(An*x + An-1)*x + ... + A1)*x + A0 11 | ; 12 | ; In other words, we start with An, multiply by x, add An-1, multiply by x, and so on, 13 | ; until we reach A0. Fill in the following template to produce a procedure that evaluates 14 | ; a polynomial using Horner's rule. Assume that the coefficients of the polynomial are arranged in a sequence, from A0 through an. 15 | 16 | ; (define (horner-eval x coefficient-sequence) 17 | ; (accumulate (lambda (this-coeff higher-terms) ) 18 | ; 0 19 | ; coefficient-sequence)) 20 | ; 21 | ;For example, to compute 1 + 3x + 5x3 + x5 at x = 2 you would evaluate 22 | ; 23 | ;(horner-eval 2 (list 1 3 0 5 0 1)) 24 | ;---------------------------------------------------------------------- 25 | 26 | (load "../helpers.scm") 27 | (load "2.2.scm") 28 | 29 | (define (horner-eval x coefficient-sequence) 30 | (accumulate (lambda (this-coeff higher-terms) (+ this-coeff (* x higher-terms))) 31 | 0 32 | coefficient-sequence)) 33 | 34 | (output (horner-eval 2 (list 1 3 0 5 0 1))) 35 | -------------------------------------------------------------------------------- /2.2/e-2.31.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 2.31. 2 | ; 3 | ; Abstract your answer to exercise 2.30 to produce a procedure tree-map 4 | ; with the property that square-tree could be defined as 5 | 6 | ; (define (square-tree tree) (tree-map square tree)) 7 | ; ------------------------------------------------------- 8 | 9 | (load "../common.scm") 10 | (load "../helpers.scm") 11 | 12 | ; generalizing traversion of the tree with tree-map function 13 | (define (tree-map mapper tree) 14 | (cond ((null? tree) nil) 15 | ((not (pair? tree)) (mapper tree)) 16 | (else (cons (tree-map mapper (car tree)) 17 | (tree-map mapper (cdr tree)))))) 18 | 19 | (define (square-tree tree) 20 | (tree-map square tree)) 21 | 22 | (output (square-tree (list 1 (list 2 3) 4 (list 5 6)))) 23 | (output (square-tree (list 5 (list (list 10 20) (list 10 20))))) 24 | 25 | ; otherwise, tree mapping can be done by applying map to sequence of sub 26 | ; trees 27 | (define (tree-map mapper tree) 28 | (map (lambda (sub-tree) 29 | (if (pair? sub-tree) 30 | (tree-map mapper sub-tree) 31 | (mapper sub-tree))) 32 | tree)) 33 | 34 | (define (square-tree tree) 35 | (tree-map square tree)) 36 | 37 | ; this give same results 38 | (output (square-tree (list 1 (list 2 3) 4 (list 5 6)))) 39 | (output (square-tree (list 5 (list (list 10 20) (list 10 20))))) 40 | 41 | -------------------------------------------------------------------------------- /2.2/e-2.47.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 2.47. Here are two possible constructors for frames: 2 | 3 | (define (make-frame origin edge1 edge2) 4 | (list origin edge1 edge2)) 5 | 6 | 7 | ; For each constructor supply the appropriate selectors to produce an 8 | ; implementation for frames. 9 | ; -------------------------------------------------- 10 | 11 | (load "../helpers.scm") 12 | (load "e-2.46.scm") 13 | 14 | ; Selectors have to pull appropriate element out of the representation. 15 | ; Point here is that interface towards outside world wil be the same in 16 | ; both cases, only internals are going to be different. 17 | 18 | ; in first case 19 | (define (origin-frame frame) 20 | (car frame)) 21 | 22 | (define (edge1-frame frame) 23 | (cadr frame)) 24 | 25 | (define (edge2-frame frame) 26 | (caddr frame)) 27 | 28 | (define test-frame 29 | (make-frame 30 | (make-vect 0 0) 31 | (make-vect 0.5 0.5) 32 | (make-vect 1 1))) 33 | 34 | (output (origin-frame test-frame)) 35 | (output (edge1-frame test-frame)) 36 | (output (edge2-frame test-frame)) 37 | 38 | ; In second case 39 | (define (make-frame origin edge1 edge2) 40 | (cons origin (cons edge1 edge2))) 41 | 42 | ; we have to redefine only last selector to take second cdr directly 43 | ; instead of pulling it out from the list with additional car 44 | (define (edge2-frame frame) 45 | (cddr frame)) 46 | 47 | 48 | -------------------------------------------------------------------------------- /2.3/e-2.54.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 2.54. 2 | ; 3 | ; Two lists are said to be equal? if they contain equal elements 4 | ; arranged in the same order. For example, 5 | 6 | ; (equal? '(this is a list) '(this is a list)) 7 | 8 | ; is true, but 9 | 10 | ; (equal? '(this is a list) '(this (is a) list)) 11 | 12 | ; is false. To be more precise, we can define equal? recursively in 13 | ; terms of the basic eq? equality of symbols by saying that a and b are 14 | ; equal? if they are both symbols and the symbols are eq?, or if they 15 | ; are both lists such that (car a) is equal? to (car b) and (cdr a) is 16 | ; equal? to (cdr b). Using this idea, implement equal? as a procedure. 17 | ; ------------------------------------------------------------ 18 | 19 | (load "../common.scm") 20 | (load "../helpers.scm") 21 | (load "2.3.scm") 22 | 23 | (define (equal? first second) 24 | (cond ((and (null? first) (null? second)) true) 25 | ((and (not (and (symbol? (car first)) 26 | (symbol? (car second)) 27 | (eq? (car first) (car second)))) 28 | (not (and (list? (car first)) 29 | (list? (car second)) 30 | (equal? (car first) (car second))))) 31 | false) 32 | (else (equal? (cdr first) (cdr second))))) 33 | 34 | (output (equal? '(this is (test (test)) list) '(this is (test (test)) list))) 35 | -------------------------------------------------------------------------------- /3.3/e-3.31.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 3.31. 2 | ; 3 | ; The internal procedure accept-action-procedure! defined in 4 | ; make-wire specifies that when a new action procedure is added to a wire, the 5 | ; procedure is immediately run. Explain why this initialization is necessary. 6 | ; In particular, trace through the half-adder example in the paragraphs above 7 | ; and say how the system's response would differ if we had defined 8 | ; accept-action-procedure! as 9 | ; 10 | ; (define (accept-action-procedure! proc) 11 | ; (set! action-procedures (cons proc action-procedures))) 12 | ; 13 | ; ------------------------------------------------------------ 14 | 15 | ; Currently accept-action-procedure! is defined as 16 | (define (accept-action-procedure! proc) 17 | (set! action-procedures (cons proc action-procedures)) 18 | (proc)) 19 | 20 | ; which is executing the added procedure immediately. 21 | ; On the example of half adder we can see what is the difference in the response 22 | ; when it is not executed immediately. 23 | ; 24 | ; The point is that if we don't call it in the point of time we add it to the list 25 | ; of actions we will not add it to agenda. In that case we will add 26 | ; it to the agenda only when we call (propagate) procedure which will produce 27 | ; different results. In fact if we don't do it, no procedures will be in the agenda at all, so 28 | ; our simulation will just not run. 29 | -------------------------------------------------------------------------------- /2.3/e-2.62.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 2.62. 2 | ; 3 | ; Give a O(n) implementation of union-set for sets 4 | ; represented as ordered lists. 5 | ; ------------------------------------------------------------ 6 | 7 | ; in order to achieve this we have to use the fact our lists are ordered 8 | ; and to decide to reduce the problem as early as possible to achieve 9 | ; the best efficiency. 10 | 11 | ; Union is defined as set of all elements that can be found in first or 12 | ; in the second set. 13 | 14 | (load "../helpers.scm") 15 | 16 | ; set has to remain ordered so in implementation we take the smaller one 17 | ; to cons it up, and then reduce the problem to the smaller subsets. 18 | ; Ordering maintains the uniqueness so I don't have to check every time 19 | ; if there is a element in the set. 20 | (define (union-set set1 set2) 21 | (cond ((null? set1) set2) 22 | ((null? set2) set1) 23 | (else 24 | (let ((x1 (car set1)) (x2 (car set2))) 25 | (cond ((= x1 x2) (cons x1 (union-set (cdr set1) (cdr set2)))) 26 | ((< x1 x2) (cons x1 (union-set (cdr set1) set2))) 27 | ((> x1 x2) (cons x2 (union-set set1 (cdr set2))))))))) 28 | 29 | ; (output (union-set (list 1 2 3) (list 1 2 3))) 30 | ; (output (union-set (list 1 2 3) (list 2 3 4))) 31 | ; (output (union-set (list 2 3 4) (list 1 2 3))) 32 | ; (output (union-set (list 2 3 4 5 6 7) (list 1 2 3 8))) 33 | -------------------------------------------------------------------------------- /3.5/e-3.69.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 3.69. 2 | ; 3 | ; Write a procedure triples that takes three infinite 4 | ; streams, S, T, and U, and produces the stream of triples (Si,Tj,Uk) 5 | ; such that i <= j <= k. Use triples to generate the stream of all 6 | ; Pythagorean triples of positive integers, i.e., the triples (i,j,k) 7 | ; such that i <= j and i^2 + j^2 = k^2. 8 | ; ------------------------------------------------------------ 9 | 10 | (load "../helpers.scm") 11 | (load "3.5.scm") 12 | 13 | ; We do this by putting one outer iteration around all pairs. 14 | ; So for 15 | (define (triples s t u) 16 | (cons-stream 17 | (list (stream-car s) (stream-car t) (stream-car u)) 18 | (interleave 19 | (stream-map (lambda (x) (cons (stream-car s) x)) (pairs t (stream-cdr u))) 20 | (triples (stream-cdr s) (stream-cdr t) (stream-cdr u))))) 21 | 22 | ; (display-stream-head (triples integers integers integers) 100) 23 | 24 | (define int-triplets (triples integers integers integers)) 25 | (define (pythagorean-filter triplet) 26 | (let ((i (car triplet)) 27 | (j (cadr triplet)) 28 | (k (caddr triplet))) 29 | (= (+ (square i) (square j)) (square k)))) 30 | 31 | (define pythagorian-triples (stream-filter pythagorean-filter int-triplets)) 32 | 33 | (display-stream-head pythagorian-triples 10) 34 | ; (3 4 5) (6 8 10) (5 12 13) ... it just takes some time because they 35 | ; are not that often in the sequence 36 | -------------------------------------------------------------------------------- /2.2/e-2.46.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 2.46. A two-dimensional vector v running from the origin to 2 | ; a point can be represented as a pair consisting of an x-coordinate and 3 | ; a y-coordinate. Implement a data abstraction for vectors by giving a 4 | ; constructor make-vect and corresponding selectors xcor-vect and 5 | ; ycor-vect. In terms of your selectors and constructor, implement 6 | ; procedures add-vect, sub-vect, and scale-vect that perform the 7 | ; operations vector addition, vector subtraction, and multiplying a 8 | ; vector by a scalar: 9 | ; 10 | ; (x1, y1) + (x2, y2) = (x1 + x2, y1 + y2) 11 | ; (x1, y1) - (x2, y2) = (x1 - x2, y1 - y2) 12 | ; s*(x, y) = (s*x, s*y) 13 | ; 14 | ;------------------------------ 15 | 16 | ; First lets define the abstraction with constructor and selectors 17 | 18 | (define (make-vect x y) 19 | (cons x y)) 20 | 21 | (define (xcor-vect vect) 22 | (car vect)) 23 | 24 | (define (ycor-vect vect) 25 | (cdr vect)) 26 | 27 | 28 | ; and now vector arithmetics 29 | (define (add-vect v1 v2) 30 | (make-vect (+ (xcor-vect v1) 31 | (xcor-vect v2)) 32 | (+ (ycor-vect v1) 33 | (ycor-vect v2)))) 34 | 35 | (define (sub-vect v1 v2) 36 | (make-vect (- (xcor-vect v1) 37 | (xcor-vect v2)) 38 | (- (ycor-vect v1) 39 | (ycor-vect v2)))) 40 | 41 | (define (scale-vect s v) 42 | (make-vect (* s (xcor-vect v)) 43 | (* s (ycor-vect v)))) 44 | -------------------------------------------------------------------------------- /3.3/e-3.14.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 3.14. The following procedure is quite useful, although 2 | ; obscure: 3 | 4 | (define (mystery x) 5 | (define (loop x y) 6 | (if (null? x) 7 | y 8 | (let ((temp (cdr x))) 9 | (set-cdr! x y) 10 | (loop temp x)))) 11 | (loop x '())) 12 | 13 | ; Loop uses the ``temporary'' variable temp to hold the old value of the 14 | ; cdr of x, since the set-cdr! on the next line destroys the cdr. 15 | ; Explain what mystery does in general. Suppose v is defined by (define 16 | ; v (list 'a 'b 'c 'd)). Draw the box-and-pointer diagram that 17 | ; represents the list to which v is bound. Suppose that we now evaluate 18 | ; (define w (mystery v)). Draw box-and-pointer diagrams that show the 19 | ; structures v and w after evaluating this expression. What would be 20 | ; printed as the values of v and w ? 21 | ; ------------------------------------------------------------ 22 | 23 | (load "../helpers.scm") 24 | 25 | (define v (list 'a 'b 'c 'd)) 26 | (define w (mystery v)) 27 | (output w) ; (d c b a) 28 | (output v) ; (a) 29 | 30 | ; This is really a mystery to be solved :) 31 | ; 32 | ; In first iteration we do pass original x to the loop, 33 | ; and inside the loop we do mutation on it. There we define temp 34 | ; variable which is in second loop passed as x and then mutations aer 35 | ; done on it now, not on original x. So original x stays changed only 36 | ; to be (a) as result of first iteration. 37 | -------------------------------------------------------------------------------- /2.2/e-2.36.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 2.36. 2 | ; 3 | ; The procedure accumulate-n is similar to accumulate except that it takes as 4 | ; its third argument a sequence of sequences, which are all assumed to have 5 | ; the same number of elements. It applies the designated accumulation procedure 6 | ; to combine all the first elements of the sequences, all the second elements 7 | ; of the sequences, and so on, and returns a sequence of the results. 8 | ; 9 | ; For instance, if s is a sequence containing four sequences, 10 | ; ((1 2 3) (4 5 6) (7 8 9) (10 11 12)), then the value of (accumulate-n + 0 s) 11 | ; should be the sequence (22 26 30). 12 | ; 13 | ; Fill in the missing expressions in the following definition of accumulate-n: 14 | 15 | ; (define (accumulate-n op init seqs) 16 | ; (if (null? (car seqs)) 17 | ; nil 18 | ; (cons (accumulate op init ) 19 | ; (accumulate-n op init )))) 20 | ; 21 | ; --------------------------------------------------------- 22 | 23 | (load "../helpers.scm") 24 | (load "../common.scm") 25 | (load "2.2.scm") 26 | 27 | (define (accumulate-n op init seqs) 28 | (if (null? (car seqs)) 29 | nil 30 | (cons (accumulate op init (map car seqs)) ; get cars of every list inside 31 | (accumulate-n op init (map cdr seqs))))) ; proceed with cadrs in next recursion 32 | 33 | ; as expected this returns 34 | ; (output (accumulate-n + 0 (list (list 1 2 3) (list 4 5 6) (list 7 8 9) (list 10 11 12)))) 35 | -------------------------------------------------------------------------------- /3.3/e-3.36.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 3.36. 2 | ; 3 | ; Suppose we evaluate the following sequence of 4 | ; expressions in the global environment: 5 | 6 | ; (define a (make-connector)) 7 | ; (define b (make-connector)) 8 | ; (set-value! a 10 'user) 9 | 10 | ; At some time during evaluation of the set-value!, the following 11 | ; expression from the connector's local procedure is evaluated: 12 | 13 | ; (for-each-except setter inform-about-value constraints) 14 | 15 | ; Draw an environment diagram showing the environment in which the above 16 | ; expression is evaluated. 17 | ; ------------------------------------------------------------ 18 | 19 | ; complex drawing on paper. 20 | ; 21 | ; First we have to draw set of definitions in the global space. 22 | ; 23 | ; Second we have to make connectors which create two execution environments 24 | ; that hold local state and procedures which are loal to that execution environment 25 | ; 26 | ; Third, we create the call stack for the set-value! procedure executed in global environment 27 | ; and then can see how procedures change state of the existing execution environments, how they 28 | ; relate to them and in which environment (for-each-except) is executed and how its execution environment 29 | ; looks like. 30 | ; 31 | ; 32 | ; 33 | ; 34 | ; Sidenote: 35 | ; I hope to buy scanner these days to scan some hand drawn environment diagrams, but my expectations 36 | ; are fairly low since my drawing skills are approximating zero. 37 | -------------------------------------------------------------------------------- /3.2/e-3.11.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 3.11. In section 3.2.3 we saw how the environment model 2 | ; described the behavior of procedures with local state. Now we have 3 | ; seen how internal definitions work. A typical message-passing 4 | ; procedure contains both of these aspects. Consider the bank account 5 | ; procedure of section 3.1.1: 6 | 7 | (define (make-account balance) 8 | (define (withdraw amount) 9 | (if (>= balance amount) 10 | (begin (set! balance (- balance amount)) 11 | balance) 12 | "Insufficient funds")) 13 | (define (deposit amount) 14 | (set! balance (+ balance amount)) 15 | balance) 16 | (define (dispatch m) 17 | (cond ((eq? m 'withdraw) withdraw) 18 | ((eq? m 'deposit) deposit) 19 | (else (error "Unknown request -- MAKE-ACCOUNT" 20 | m)))) 21 | dispatch) 22 | 23 | ; Show the environment structure generated by the sequence of 24 | ; interactions 25 | 26 | (define acc (make-account 50)) 27 | 28 | ((acc 'deposit) 40) 29 | 90 30 | 31 | ((acc 'withdraw) 60) 32 | 30 33 | 34 | ; Where is the local state for acc kept? Suppose we define another 35 | ; account 36 | 37 | (define acc2 (make-account 100)) 38 | 39 | ; How are the local states for the two accounts kept distinct? Which 40 | ; parts of the environment structure are shared between acc and acc2? 41 | ; 42 | ; @see http://mitpress.mit.edu/sicp/full-text/book/book-Z-H-21.html#%_sec_3.2.4 43 | ; for guide how to draw the rames for this case. 44 | -------------------------------------------------------------------------------- /3.3/3.3.scm: -------------------------------------------------------------------------------- 1 | ; Modeling with mutable data 2 | ; 3 | ; Until now we worked only with non-mutable cons, car and cdr 4 | ; procedures. 5 | ; But, we can see this a bit differently. Cons can be defined as two 6 | ; mutations that set car and cdr 7 | 8 | ; (define (cons x y) 9 | ; (let ((new (get-new-pair))) 10 | ; (set-car! new x) 11 | ; (set-cdr! new y) 12 | ; new)) 13 | 14 | ; where (get-new-pair) is the constructor of the empty pair 15 | 16 | ; history list that gives us way to store and see if there is something inside 17 | (define history 18 | ; setting initial history it to null so append have to what to append actually ;) 19 | (let ((visited-list (cons '() '()))) 20 | 21 | (define (visited? x) 22 | (define (iter visited-list x) 23 | (cond ((null? visited-list) '#f) 24 | ((eq? (car visited-list) x) '#t) 25 | (else (iter (cdr visited-list) x)))) 26 | (iter visited-list x)) 27 | 28 | (define (add x) 29 | (append! visited-list (cons x '())) 30 | visited-list) 31 | 32 | (lambda (m) 33 | (cond ((eq? m 'add) add) 34 | ((eq? m 'visited?) visited?) 35 | ((eq? m 'reset) (set! visited-list (cons '() '()))) 36 | (else (error "Unknow operation on history")))))) 37 | 38 | (define (append! x y) 39 | (set-cdr! (last-pair x) y) 40 | x) 41 | 42 | ; getting the last pair of the list 43 | (define (last-pair x) 44 | (if (null? (cdr x)) 45 | x 46 | (last-pair (cdr x)))) 47 | -------------------------------------------------------------------------------- /1.2/e-1.16.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 1.16. 2 | ; 3 | ; Design a procedure that evolves an iterative exponentiation process that uses successive 4 | ; squaring and uses a logarithmic number of steps, as does fast-expt. 5 | ; (Hint: Using the observation that (b^(n/2))^2 = (b^2)^(n/2), keep, along with the exponent 6 | ; n and the base b, an additional state variable a, and define the state transformation in 7 | ; such a way that the product a bn is unchanged from state to state. At the beginning of 8 | ; the process a is taken to be 1, and the answer is given by the value of a at the end of the 9 | ; process. In general, the technique of defining an invariant quantity that remains unchanged 10 | ; from state to state is a powerful way to think about the design of iterative algorithms.) 11 | ; 12 | ; ----------------------------- 13 | ; 14 | 15 | ; We have to introduce product that will be passed through iterations, 16 | ; as suggested in the task. One porblem is that the way fast-expt in 17 | ; example is given it doesn't allow us to pass n to next iteration. By 18 | ; putting n out of squaring by transforming (b^(n/2))^2 => (b^2)^(n/2) 19 | ; we can write following procedure. 20 | ; 21 | 22 | (load "../common.scm") 23 | 24 | (define (expt b n) 25 | (fast-expt b n 1)) 26 | 27 | (define (fast-expt b n product) 28 | (cond ((= n 0) product) 29 | ((even? n) (fast-expt (square b) (/ n 2) product)) 30 | (else (fast-expt b (- n 1) (* product b))))) 31 | 32 | ; (display (expt 2 30)) 33 | ; (newline) 34 | 35 | -------------------------------------------------------------------------------- /1.2/e-1.26.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 1.26. 2 | ; 3 | ; Louis Reasoner is having great difficulty doing exercise 1.24. His fast-prime? test seems to run more slowly 4 | ; than his prime? test. Louis calls his friend Eva Lu Ator over to help. 5 | ; When they examine Louis's code, they find that he has rewritten the 6 | ; expmod procedure to use an explicit multiplication, rather than calling square: 7 | 8 | (define (expmod base exp m) 9 | (cond ((= exp 0) 1) 10 | ((even? exp) 11 | (remainder (* (expmod base (/ exp 2) m) 12 | (expmod base (/ exp 2) m)) 13 | m)) 14 | (else 15 | (remainder (* base (expmod base (- exp 1) m)) 16 | m)))) 17 | 18 | ; ``I don't see what difference that could make,'' says Louis. 19 | ; ``I do.'' says Eva. ``By writing the procedure like that, you have transformed the (log n) process into a (n) process.'' Explain. 20 | ; ----------------------------- 21 | ; 22 | ; If we know that applicative substitution evaluates parameters every time then 23 | ; it is evaluating 2 times expmod for every expmod call. Therefore, despite the 24 | ; fact we are halving the problem we are doubling the number of calls. So at the 25 | ; end we are cancelling logarithm with exponend and then getting to the O(n) 26 | ; order of growth. 27 | ; 28 | ; The one that do squaring instead of multiplication has only one call per 29 | ; recursion and with halving the size of the problem every time it is converging 30 | ; logarithmicaly. 31 | -------------------------------------------------------------------------------- /3.5/e-3.76.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 3.76. 2 | ; 3 | ; Eva Lu Ator has a criticism of Louis's approach in 4 | ; exercise 3.75. The program he wrote is not modular, because it 5 | ; intermixes the operation of smoothing with the zero-crossing 6 | ; extraction. For example, the extractor should not have to be changed 7 | ; if Alyssa finds a better way to condition her input signal. Help Louis 8 | ; by writing a procedure smooth that takes a stream as input and 9 | ; produces a stream in which each element is the average of two 10 | ; successive input stream elements. Then use smooth as a component to 11 | ; implement the zero-crossing detector in a more modular style. 12 | ; ------------------------------------------------------------ 13 | 14 | ; The program in 3.75 was implemented more in the structured programming 15 | ; style where in one iterative process we put lot of calculations that 16 | ; depend on the current value of certain variable. 17 | ; 18 | ; We can chain stream with stream operations that we already have 19 | (load "../helpers.scm") 20 | (load "3.5.scm") 21 | 22 | (define sensor-stream 23 | (stream-map (lambda (x) (- (random 10) 5)) 24 | ones)) 25 | 26 | (define (average x y) 27 | (/ (+ x y) 2)) 28 | 29 | (define (smooth input-stream) 30 | (stream-map average input-stream (stream-cdr input-stream))) 31 | 32 | (define (make-zero-crossings input-stream) 33 | (stream-map sign-change-detector input-stream (stream-cdr input-stream))) 34 | 35 | (define zero-crossings (make-zero-crossings (smooth sensor-stream))) 36 | -------------------------------------------------------------------------------- /2.1/e-2.4.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 2.4. Here is an alternative procedural representation of pairs. For this representation, verify that (car (cons x y)) yields x for any objects x and y. 2 | 3 | (define (cons x y) 4 | (lambda (m) (m x y))) 5 | 6 | (define (car z) 7 | (z (lambda (p q) p))) 8 | 9 | ; What is the corresponding definition of cdr? (Hint: To verify that this works, make use of the substitution model of section 1.1.5.) 10 | ; ------------------------------------------------------ 11 | ; 12 | ; First, lets see if (car (cons x y)) returns x for any x 13 | 14 | ; first 1 and 2 are primitive ints 15 | (display (car (cons 1 2))) ; 1 16 | (newline) 17 | 18 | ; now we can try the lists, so we see that it is in fact procedure returned 19 | (display (car (cons (cons 1 2) (cons 3 4)))) 20 | (newline) 21 | 22 | ; similarly we see that it doesn't matter what x and y are in fact. But they are perceived as 23 | ; list members and returned accordingly. Here we can see the power of having procedures together 24 | ; with primitives as first-class citizens. 25 | 26 | ; Secondly, we can define cdr as 27 | 28 | (define (cdr z) 29 | (z (lambda (p q) q))) 30 | 31 | (display (cdr (cons 1 2))) ; 2 32 | (newline) 33 | 34 | ; Substitution model for cdr would look like this. 35 | 36 | (cdr (cons 1 2)) 37 | (cdr (lambda (m) (m 1 2))) ; evaluating argument of cdr 38 | ((lambda (m) (m 1 2)) (lambda (p q) q))) ; now evaluating cdr itself 39 | ((lambda (p q) q)) 1 2) ; applying operator to operand 40 | ((lambda (1 2) 2)) ; once again 41 | ; and this produces 2 42 | -------------------------------------------------------------------------------- /3.5/e-3.62.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 3.62. 2 | ; 3 | ; Use the results of exercises 3.60 and 3.61 to define a 4 | ; procedure div-series that divides two power series. Div-series should 5 | ; work for any two series, provided that the denominator series begins 6 | ; with a nonzero constant term. (If the denominator has a zero constant 7 | ; term, then div-series should signal an error.) Show how to use 8 | ; div-series together with the result of exercise 3.59 to generate the 9 | ; power series for tangent. 10 | ; ------------------------------------------------------------ 11 | 12 | (load "../helpers.scm") 13 | (load "3.5.scm") 14 | (load "e-3.59.scm") ; sin-series, cos-series 15 | (load "e-3.60.scm") ; mul-series 16 | (load "e-3.61.scm") ; invert-unit-series 17 | 18 | (define (div-series num-series den-series) 19 | (let ((den (stream-car den-series))) 20 | (if (= den 0) 21 | (error "Division by zero is not allowed") 22 | (scale-stream 23 | (mul-series 24 | num-series 25 | (invert-unit-series (scale-stream den-series (/ 1 den)))) 26 | (/ 1 den))))) 27 | 28 | (define tan-series (div-series sin-series cos-series)) 29 | 30 | (display-stream-head tan-series 10) 31 | ; The result of reading first 10 coefficients of tangent 32 | ; 33 | ; 0 1 0.0 0.333333333333333 0.0 0.133333333333333 0.0 0.053968253968254 0.0 0.0218694885361552 34 | ; 35 | ; which is correct for expanded Taylor series for tangent trig function 36 | ; http://en.wikipedia.org/wiki/Tangent_(trigonometric_function) 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /3.3/e-3.16.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 3.16. 2 | ; 3 | ; Ben Bitdiddle decides to write a procedure to count 4 | ; the number of pairs in any list structure. ``It's easy,'' he reasons. 5 | ; ``The number of pairs in any structure is the number in the car plus 6 | ; the number in the cdr plus one more to count the current pair.'' So 7 | ; Ben writes the following procedure: 8 | 9 | (define (count-pairs x) 10 | (if (not (pair? x)) 11 | 0 12 | (+ (count-pairs (car x)) 13 | (count-pairs (cdr x)) 14 | 1))) 15 | 16 | ; Show that this procedure is not correct. In particular, draw 17 | ; box-and-pointer diagrams representing list structures made up of 18 | ; exactly three pairs for which Ben's procedure would return 3; return 19 | ; 4; return 7; never return at all. 20 | ; ------------------------------------------------------------ 21 | 22 | (load "../helpers.scm") 23 | 24 | ; The straightforward definition will return actually 3 25 | (define l (list 1 2 3)) ; three pairs, linked in a list 26 | (output (count-pairs l)) 27 | 28 | (define first (cons 1 2)) 29 | (define second (cons 1 2)) 30 | (define third (cons first second)) 31 | (set-car! second first) 32 | (output (count-pairs third)) ; 4 33 | 34 | (define first (cons 1 2)) 35 | (define second (cons first first)) 36 | (define third (cons second second)) 37 | (output (count-pairs third)) 38 | 39 | ; It will never return if there is a cycle in the data structure. 40 | (define x (list 1 2 3)) 41 | (set-cdr! x x) ; three pairs cycled 42 | (output (count-pairs x)) 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /1.1/e-1.6.scm: -------------------------------------------------------------------------------- 1 | (define (new-if predicate then-clause else-clause) 2 | (cond (predicate then-clause) 3 | (else else-clause))) 4 | 5 | ; (display (new-if (> 2 3) 5 6)) 6 | 7 | ; Square root expressed in terms of new-if method 8 | 9 | (define (improve guess x) 10 | (average guess (/ x guess))) 11 | 12 | (define (average x y) 13 | (/ (+ x y) 2)) 14 | 15 | (define (square x) 16 | (* x x)) 17 | 18 | (define (good-enough? guess x) 19 | (< (abs (- (square guess) x)) 0.001)) 20 | 21 | (define (sqrt-iter guess x) 22 | (new-if (good-enough? guess x) 23 | guess 24 | (sqrt-iter (improve guess x) x))) 25 | 26 | (define (sqrt x) 27 | (sqrt-iter 1.0 x)) 28 | 29 | ; (display (sqrt 36)) 30 | 31 | ; Although we would expect same result of our function as we would 32 | ; with primitive if operator, we get the information that Stack Level 33 | ; got too deep during execution. 34 | ; 35 | ; Difference is that new-if method evaluates in the normal order 36 | ; comparing to applicative order of evaluation which is applied to the 37 | ; primitive procedures. 38 | ; 39 | ; Normal order is such that compound procedures are evaluated but 40 | ; arguments are not until whole statement is comprised only of primitive 41 | ; operations. In this case recursion doesn't end and sqrt-iter is 42 | ; evaluated repeatedly until we get to Stack Level too deep message. 43 | ; If parameters where to be evaluated in every step, in one moment 44 | ; good-enough? would return true and loop would be stopped and `rolled 45 | ; back` to root of recursion. 46 | -------------------------------------------------------------------------------- /3.1/e-3.3.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 3.3. Modify the make-account procedure so that it creates 2 | ; password-protected accounts. That is, make-account should take a 3 | ; symbol as an additional argument, as in 4 | 5 | ; (define acc (make-account 100 'secret-password)) 6 | 7 | ; The resulting account object should process a request only if it is 8 | ; accompanied by the password with which the account was created, and 9 | ; should otherwise return a complaint: 10 | 11 | ; ((acc 'secret-password 'withdraw) 40) ; 60 12 | 13 | ; ((acc 'some-other-password 'deposit) 50) ; "Incorrect password" 14 | ; ------------------------------------------------------------ 15 | 16 | (load "../helpers.scm") 17 | 18 | (define (make-account balance account-password) 19 | (define (withdraw amount) 20 | (if (>= balance amount) 21 | (begin (set! balance (- balance amount)) 22 | balance) 23 | "Insufficient funds")) 24 | (define (deposit amount) 25 | (set! balance (+ balance amount)) 26 | balance) 27 | ; action dispatcher, protected by password 28 | (lambda (password m) 29 | (if (eq? password account-password) 30 | (cond ((eq? m 'withdraw) withdraw) 31 | ((eq? m 'deposit) deposit) 32 | (else (error "Unknown request -- MAKE-ACCOUNT" m))) 33 | ; just return complaint, but has to accept argument 34 | (lambda (n) "Incorrect password")))) 35 | 36 | 37 | (define acc (make-account 100 'wizards!lizards)) 38 | (output ((acc 'wizards!lizards 'withdraw) 40)) 39 | (output ((acc 'lizards!wizards 'withdraw) 40)) 40 | -------------------------------------------------------------------------------- /3.3/e-3.18.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 3.18. 2 | ; 3 | ; Write a procedure that examines a list and 4 | ; determines whether it contains a cycle, that is, whether a 5 | ; program that tried to find the end of the list by taking 6 | ; successive cdrs would go into an infinite loop. Exercise 3.13 7 | ; constructed such lists. 8 | ; ------------------------------------------------------------ 9 | 10 | ; I guess, the way to go there is to go through the list and if 11 | ; we end in a situation to get to the pair that has pointer to 12 | ; a pair that is already traversed then we are definitelly going to 13 | ; end up cycling through them. 14 | 15 | (load "../helpers.scm") 16 | (load "3.3.scm") 17 | 18 | ; by reusing history object, it is actually simple to write this 19 | (define (cycled? l) 20 | (cond ((or (null? l) (not (pair? l))) '#f) 21 | ((null? (cdr l)) '#f) 22 | (((history 'visited?) (cdr l)) '#t) 23 | (else 24 | (begin ((history 'add) l) 25 | (or (cycled? (car l)) 26 | (cycled? (cdr l))))))) 27 | 28 | ; we have to reset global history object every time. 29 | ; This can be improved by making new history local to the cycled? procedure. 30 | (output (cycled? (list 1 2 3))) ; #f 31 | (history 'reset) 32 | 33 | (define l (list 1 2 3)) 34 | (append! l l) ; cycle 35 | 36 | (history 'reset) 37 | (output (cycled? l)) ; #t 38 | 39 | (define m (list 1 2 3)) 40 | (define n (list 1 2 3)) 41 | (append! m n) 42 | 43 | (history 'reset) 44 | (output (cycled? m)) 45 | 46 | (history 'reset) 47 | (output (cycled? n)) 48 | -------------------------------------------------------------------------------- /4.1/e-4.21.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 4.21. Amazingly, Louis's intuition in exercise 4.20 is correct. It 2 | ; is indeed possible to specify recursive procedures without using letrec (or 3 | ; even define), although the method for accomplishing this is much more subtle 4 | ; than Louis imagined. The following expression computes 10 factorial by 5 | ; applying a recursive factorial procedure:27 6 | 7 | ;((lambda (n) 8 | ;((lambda (fact) 9 | ;(fact fact n)) 10 | ;(lambda (ft k) 11 | ;(if (= k 1) 12 | ;1 13 | ;(* k (ft ft (- k 1))))))) 14 | ;10) 15 | 16 | ; a. Check (by evaluating the expression) that this really does compute 17 | ; factorials. Devise an analogous expression for computing Fibonacci numbers. 18 | 19 | ; b. Consider the following procedure, which includes mutually recursive 20 | ; internal definitions: 21 | 22 | ;(define (f x) 23 | ;(define (even? n) 24 | ;(if (= n 0) 25 | ;true 26 | ;(odd? (- n 1)))) 27 | ;(define (odd? n) 28 | ;(if (= n 0) 29 | ;false 30 | ;(even? (- n 1)))) 31 | ;(even? x)) 32 | 33 | ; Fill in the missing expressions to complete an alternative definition of f, 34 | ; which uses neither internal definitions nor letrec: 35 | 36 | ;(define (f x) 37 | ;((lambda (even? odd?) 38 | ;(even? even? odd? x)) 39 | ;(lambda (ev? od? n) 40 | ;(if (= n 0) true (od? ))) 41 | ;(lambda (ev? od? n) 42 | ;(if (= n 0) false (ev? ))))) 43 | 44 | ; ------------------------------------------------------------ 45 | 46 | ; a) 47 | ; 48 | -------------------------------------------------------------------------------- /3.5/e-3.67.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 3.67. 2 | ; 3 | ; Modify the pairs procedure so that (pairs integers 4 | ; integers) will produce the stream of all pairs of integers (i,j) 5 | ; (without the condition i < j). Hint: You will need to mix in an 6 | ; additional stream. 7 | ; ------------------------------------------------------------ 8 | 9 | (load "../helpers.scm") 10 | (load "3.5.scm") 11 | 12 | ; current implementation of the mentioned procedure 13 | (define (pairs s t) 14 | (cons-stream 15 | (list (stream-car s) (stream-car t)) 16 | (interleave 17 | (stream-map (lambda (x) (list (stream-car s) x)) 18 | (stream-cdr t)) 19 | (pairs (stream-cdr s) (stream-cdr t))))) 20 | 21 | (define (interleave s1 s2) 22 | (if (stream-null? s1) 23 | s2 24 | (cons-stream (stream-car s1) 25 | (interleave s2 (stream-cdr s1))))) 26 | 27 | (define int-pairs (pairs integers integers)) 28 | 29 | 30 | 31 | 32 | ; Our implementation of all pairs can map over the stream of pairs to 33 | ; make just the inversion of the elements if they are different or to 34 | ; emit null element if same 35 | 36 | (define (swap-pair pair) ; represented as list of two elements, not cons 37 | (if (= (car pair) (cadr pair)) 38 | '() ; if they are same don't emit one more like that 39 | (list (cadr pair) (car pair)))) 40 | 41 | (define all-pairs 42 | (interleave 43 | int-pairs 44 | (stream-filter (lambda (x) (not (null? x))) (stream-map swap-pair int-pairs)))) 45 | 46 | ; small test to see if this works 47 | ; (display-stream-head all-pairs 20) ; it works 48 | -------------------------------------------------------------------------------- /3.2/e-3.10.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 3.10. In the make-withdraw procedure, the local variable 2 | ; balance is created as a parameter of make-withdraw. We could also 3 | ; create the local state variable explicitly, using let, as follows: 4 | 5 | (define (make-withdraw initial-amount) 6 | (let ((balance initial-amount)) 7 | (lambda (amount) 8 | (if (>= balance amount) 9 | (begin (set! balance (- balance amount)) 10 | balance) 11 | "Insufficient funds")))) 12 | 13 | ; Recall from section 1.3.2 that let is simply syntactic sugar for a 14 | ; procedure call: 15 | 16 | (let (( )) ) 17 | 18 | ; is interpreted as an alternate syntax for 19 | 20 | ((lambda () ) ) 21 | 22 | ; Use the environment model to analyze this alternate version of 23 | ; make-withdraw, drawing figures like the ones above to illustrate the 24 | ; interactions 25 | 26 | (define W1 (make-withdraw 100)) 27 | 28 | (W1 50) 29 | 30 | (define W2 (make-withdraw 100)) 31 | 32 | ; Show that the two versions of make-withdraw create objects with the 33 | ; same behavior. How do the environment structures differ for the two 34 | ; versions? 35 | ; ------------------------------------------------------------ 36 | 37 | ; Point here is that (let) is only the sytactic sugar for the (lambda) 38 | ; which is the only way to create procedure. Let, in this case defines 39 | ; new procedure and immediatelly executes it so we'll have different 40 | ; structure of the environments with oe more intermediate for the 41 | ; overall execution, but result will be the same. 42 | ; 43 | ; 44 | -------------------------------------------------------------------------------- /3.4/e-3.39.scm: -------------------------------------------------------------------------------- 1 | (define x 10) 2 | 3 | (parallel-execute (lambda () (set! x (* x x))) 4 | (lambda () (set! x (+ x 1)))) 5 | 6 | ; This creates two concurrent processes -- P1, which sets x to x times 7 | ; x, and P2, which increments x. After execution is complete, x will be 8 | ; left with one of five possible values, depending on the interleaving 9 | ; of the events of P1 and P2: 10 | ; 101: P1 sets x to 100 and then P2 increments x to 101. 11 | ; 121: P2 increments x to 11 and then P1 sets x to x times x. 12 | ; 110: P2 changes x from 10 to 11 between the two times that P1 accesses the value of x 13 | ; during the evaluation of (* x x). 14 | ; 11: P2 accesses x, then P1 sets x to100, then P2 sets x. 15 | ; 100: P1 accesses x (twice), then P2 sets x to 11, then P1 sets x. 16 | 17 | 18 | ; Exercise 3.39. Which of the five possibilities in the parallel 19 | ; execution shown above remain if we instead serialize execution as 20 | ; follows: 21 | 22 | (define x 10) 23 | 24 | (define s (make-serializer)) 25 | 26 | (parallel-execute (lambda () (set! x ((s (lambda () (* x x)))))) 27 | (s (lambda () (set! x (+ x 1))))) 28 | 29 | 30 | ; ------------------------------------------------------------ 31 | 32 | ; All solutions in which second procedure was interrupted in the middle 33 | ; of execution are now prevented. So it will be possible to have only 34 | ; cases 35 | ; 101: P1 sets x to 100 and then P2 increments x to 101. 36 | ; 121: P2 increments x to 11 and then P1 sets x to x times x. 37 | ; 100: P1 accesses x (twice), then P2 sets x to 11, then P1 sets x. 38 | -------------------------------------------------------------------------------- /3.5/series.scm: -------------------------------------------------------------------------------- 1 | ; Throughout this chapter we have implemented small api for manipulating 2 | ; Taylor series. Here are the procedures comprising it. 3 | (load "streams.scm") 4 | 5 | (define (mul-series s1 s2) 6 | (cons-stream 7 | (* (stream-car s1) (stream-car s2)) 8 | (add-streams 9 | (add-streams (scale-stream (stream-cdr s1) 10 | (stream-car s2)) 11 | (scale-stream (stream-cdr s2) 12 | (stream-car s1))) 13 | (cons-stream 0 (mul-series (stream-cdr s1) 14 | (stream-cdr s2)))))) 15 | 16 | (define (div-series num-series den-series) 17 | (let ((den (stream-car den-series))) 18 | (if (= den 0) 19 | (error "Division by zero is not allowed") 20 | (scale-stream 21 | (mul-series 22 | num-series 23 | (invert-unit-series (scale-stream den-series (/ 1 den)))) 24 | (/ 1 den))))) 25 | 26 | (define (negate-series series) 27 | (stream-map (lambda (x) (- x)) 28 | series)) 29 | 30 | (define (integrate-series series) 31 | (mul-streams coefficients series)) 32 | 33 | (define (invert-unit-series stream) 34 | (cons-stream 1 35 | (negate-series (mul-series (stream-cdr stream) 36 | (invert-unit-series stream))))) 37 | 38 | ; some interesting series 39 | (define cos-series (cons-stream 1 (negate-series (integrate-series sin-series)))) 40 | (define sin-series (cons-stream 0 (integrate-series cos-series))) 41 | (define tan-series (div-series sin-series cos-series)) 42 | -------------------------------------------------------------------------------- /3.3/e-3.32.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 3.32. 2 | ; 3 | ; The procedures to be run during each time 4 | ; segment of the agenda are kept in a queue. Thus, the procedures 5 | ; for each segment are called in the order in which they were 6 | ; added to the agenda (first in, first out). Explain why this 7 | ; order must be used. In particular, trace the behavior of an 8 | ; and-gate whose inputs change from 0,1 to 1,0 in the same 9 | ; segment and say how the behavior would differ if we stored a 10 | ; segment's procedures in an ordinary list, adding and removing 11 | ; procedures only at the front (last in, first out). 12 | ; ------------------------------------------------------------ 13 | 14 | ; If we look at the implementation more closely, and gate ads one action per 15 | ; wire. 16 | ; 17 | ; wire a1 gets an action and wire a2 gets an action. When there is a change in 18 | ; the input signal, these two actions are producing certain events to happen 19 | ; after some delay. If we use LILO approach of the queue, these actions are 20 | ; set in a proper order of execution and the end result is OK, otherwise we get 21 | ; the wrong result. 22 | ; 23 | ; Preciselly explained in comment: http://eli.thegreenplace.net/2007/10/08/sicp-section-334/#comment-124196 24 | ; 25 | ; set-signal! will add some segments to the-agenda, and the signal of z will 26 | ; change only after (propagate) is done. So that after s1, something like 27 | ; (set-signal! z 1) will be added to the-agenda, and s2 will add (set-signal! z 28 | ; 0). Here is the difference: if the LIFO queue is used, (propagate) will run 29 | ; (set-signal! z 0) first instead of (set-signal! z 1). 30 | -------------------------------------------------------------------------------- /3.5/e-3.80.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 3.80. A series RLC circuit consists of a resistor, a 2 | ; capacitor, and an inductor connected in series, as shown in figure 3 | ; 3.36. If R, L, and C are the resistance, inductance, and capacitance, 4 | ; then the relations between voltage (v) and current (i) for the three 5 | ; components are described by the equations 6 | 7 | 8 | ; and the circuit connections dictate the relations 9 | 10 | 11 | ; Combining these equations shows that the state of the circuit 12 | ; (summarized by vC, the voltage across the capacitor, and iL, the 13 | ; current in the inductor) is described by the pair of differential 14 | ; equations 15 | 16 | 17 | ; The signal-flow diagram representing this system of differential 18 | ; equations is shown in figure 3.37. 19 | 20 | 21 | ; Figure 3.36: A series RLC circuit. 22 | 23 | 24 | ; Figure 3.37: A signal-flow diagram for the solution to a series RLC 25 | ; circuit. Write a procedure RLC that takes as arguments the parameters 26 | ; R, L, and C of the circuit and the time increment dt. In a manner 27 | ; similar to that of the RC procedure of exercise 3.73, RLC should 28 | ; produce a procedure that takes the initial values of the state 29 | ; variables, vC0 and iL0, and produces a pair (using cons) of the 30 | ; streams of states vC and iL. Using RLC, generate the pair of streams 31 | ; that models the behavior of a series RLC circuit with R = 1 ohm, C = 32 | ; 0.2 farad, L = 1 henry, dt = 0.1 second, and initial values iL0 = 0 33 | ; amps and vC0 = 10 volts. 34 | 35 | 36 | 37 | 38 | ; This is becoming more exercise from the basics of electronics circuits 39 | ; ;) 40 | -------------------------------------------------------------------------------- /3.5/e-3.51.scm: -------------------------------------------------------------------------------- 1 | (load "../helpers.scm") 2 | (load "3.5.scm") 3 | 4 | ; Exercise 3.51. In order to take a closer look at delayed 5 | ; evaluation, we will use the following procedure, which simply 6 | ; returns its argument after printing it: 7 | 8 | (define (show x) 9 | (output x) 10 | x) 11 | 12 | ; What does the interpreter print in response to evaluating each 13 | ; expression in the following sequence? 14 | 15 | ; (define x (stream-map show (stream-enumerate-interval 0 10))) 16 | ; (stream-ref x 5) 17 | ; (stream-ref x 7) 18 | ;------------------------------------------------------------ 19 | 20 | ; First about the definition of the exercise. Here we have a procedure 21 | ; (show x) which, when executed, will display the value of x and then return the value. 22 | ; It is useful in this case because it will tell us when certain element of the stream is 23 | ; evaluated. 24 | ; 25 | ; This approach of mixing the presentation code with the data structure is extremely bad 26 | ; example of mixing concerns and should not be regular approach in development. For this 27 | ; demonstrational purpose it serves its local purpose and nothing more. 28 | 29 | ; this one will evaluate only the first element of the stream 30 | (output "(define ...") 31 | (define x (stream-map show (stream-enumerate-interval 0 10))) 32 | 33 | ; This one will evaluate up to fifth element 34 | (output "(stream-ref x 5)") 35 | (stream-ref x 5) 36 | 37 | ; This one will evaluate up to seventh, but since first 5 are already 38 | ; evaluated, then we will not evaluate them again, so we evaluate only two more. 39 | (output "(stream-ref x 7)") 40 | (stream-ref x 7) 41 | -------------------------------------------------------------------------------- /1.3/e-1.39.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 1.39. 2 | ; A continued fraction representation of the tangent function was published 3 | ; in 1770 by the German mathematician J.H. Lambert: 4 | ; 5 | ; x 6 | ; tan x = --------------------- 7 | ; x^2 8 | ; 1 - --------------- 9 | ; x^3 10 | ; 3 - ---------- 11 | ; 5 - .... 12 | ; 13 | ; where x is in radians. 14 | ; 15 | ; Define a procedure (tan-cf x k) that computes an approximation to the tangent 16 | ; function based on Lambert's formula. K specifies the number of terms to compute, 17 | ; as in exercise 1.37. 18 | ; 19 | 20 | ; defining tan-cf and hiding specific procedures inside 21 | (define (tan-cf x k) 22 | 23 | ; copying most of the function which is defined in 1.37 24 | ; This may be even generalized with passign the sign for the 25 | ; recursive arithmetic. 26 | (define (cont-frac x n-proc d-proc k) 27 | (define (iter i result) 28 | (let ((n (n-proc x i)) 29 | (d (d-proc i))) 30 | (if (= i 1) 31 | (/ n (- d result)) 32 | (iter (- i 1) (/ n (- d result)))))) 33 | (iter k 1)) 34 | 35 | (define n-proc 36 | (lambda (x i) (exp x i))) 37 | 38 | (define d-proc 39 | (lambda (i) (- (* 2 i) 1))) 40 | 41 | (cont-frac x n-proc d-proc k)) 42 | 43 | ; (display (tan 2 10)) ; -2.185039863261519 44 | ; (newline) 45 | ; 46 | ; 47 | ; Did I say that I like iterative more than recursive definitions. 48 | ; Although recursive is easier to reason about. It is as with most 49 | ; things in life, if it is easy there must be some catch in it :) 50 | 51 | -------------------------------------------------------------------------------- /1.2/e-1.18.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 1.18 2 | ; 3 | ; Using the results of exercises 1.16 and 1.17, devise a procedure that generates 4 | ; an iterative process for multiplying two integers in terms of adding, doubling, 5 | ; and halving and uses a logarithmic number of steps. 6 | ; 7 | 8 | (load "../common.scm") 9 | (load "e-1.16.scm") 10 | 11 | ; We can do this by implementing so called Russian peasants method of multiplication. 12 | ; This method is based on conversion of one of the multiplicators to binary form 13 | ; and then multiplying other with the powers of 2 for the places where binary form 14 | ; has 1 as the value. 15 | ; 16 | ; Example: 17 | ; 18 | ; 12 * 13 19 | ; 20 | ; Converting 12 to binary form: 21 | ; 22 | ; 12 / 2 = 6 with rest 0 23 | ; 6 / 2 = 3 with rest 0 24 | ; 3 / 2 = 1 with rest 1 25 | ; 1 / 2 = 0 with rest 1 26 | ; 27 | ; so this is 1100 in binary form and it is 2^3 + 2^2. Therefore, our solution is 28 | ; 2^3 * 13 + 2^2 * 13 = 156 29 | ; 30 | ; Converted to iterative algorithm that looks like this. 31 | ; 32 | ; I reuse expt function from the exercise 1.16 which is loaded 33 | 34 | (define (mult a b) 35 | (fast-mult a b 0 0)) 36 | 37 | (define (fast-mult a b product counter) 38 | (cond ((= a 0) product) 39 | ((= (remainder a 2) 1) (fast-mult (div a 2) b (+ product (* (expt 2 counter) b)) (+ counter 1))) 40 | (else (fast-mult (div a 2) b product (+ counter 1))))) 41 | 42 | (display (mult 120 13)) 43 | (newline) 44 | ; 45 | ; Here, instead of continuously adding a times we halve the size of the problem in every iteration. 46 | ; Therefore the number of steps of the algorithm grow logaritmicaly with the size of the problem. 47 | -------------------------------------------------------------------------------- /5.4/e-5.26.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 5.26. Use the monitored stack to explore the tail-recursive 2 | ; property of the evaluator (section 5.4.2). Start the evaluator and define the 3 | ; iterative factorial procedure from section 1.2.1: 4 | 5 | (define (factorial n) 6 | (define (iter product counter) 7 | (if (> counter n) 8 | product 9 | (iter (* counter product) 10 | (+ counter 1)))) 11 | (iter 1 1)) 12 | 13 | ; Run the procedure with some small values of n. Record the maximum stack depth 14 | ; and the number of pushes required to compute n! for each of these values. 15 | 16 | ; a. You will find that the maximum depth required to evaluate n! is 17 | ; independent of n. What is that depth? 18 | 19 | ; b. Determine from your data a formula in terms of n for the total number of 20 | ; push operations used in evaluating n! for any n > 1. Note that the number of 21 | ; operations used is a linear function of n and is thus determined by two 22 | ; constants. 23 | ; ------------------------------------------------------------ 24 | 25 | ; a) The depth is indeed independent from n because it is not really doing the 26 | ; recursive calls but is just doing the iteration with same stack depth. 27 | ; n | depth | pushes 28 | ; ---------------------- 29 | ; 1 | 10 | 64 30 | ; 2 | 10 | 99 31 | ; 3 | 10 | 134 32 | ; 4 | 10 | 169 33 | ; 10 | 10 | 379 34 | 35 | ; b) This is strange, since I am using for the REPL the code authors provided and it is somewhere around 40*n + c 36 | ; but it is not linear in fact but I guess it should be. Anyway order of growth is O(n) which is important to figure out. 37 | -------------------------------------------------------------------------------- /3.5/e-3.72.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 3.72. 2 | ; 3 | ; In a similar way to exercise 3.71 generate a 4 | ; stream of all numbers that can be written as the sum of two 5 | ; squares in three different ways (showing how they can be so 6 | ; written). 7 | ; ------------------------------------------------------------ 8 | 9 | (load "e-3.70.scm") 10 | 11 | (define square-weight 12 | (lambda (pair) 13 | (let ((i (car pair)) 14 | (j (cadr pair))) 15 | (+ (* i i) (* j j))))) 16 | 17 | (define square-weighted-pairs 18 | (weighted-pairs 19 | integers 20 | integers 21 | square-weight)) 22 | 23 | ;this can be done by applying twice some more general procedure of ramanujan-stream-filter 24 | ;which will produce stream of values we need. Here is implementation for current case 25 | (define (square-weight-filter stream) 26 | (let* ((tail-of-stream (stream-cdr stream)) 27 | (weight1 (square-weight (stream-car stream))) 28 | (weight2 (square-weight (stream-car tail-of-stream))) 29 | (weight3 (square-weight (stream-car (stream-cdr tail-of-stream))))) 30 | (if (and (= weight1 weight2) (= weight2 weight3)) 31 | (cons-stream 32 | weight1 33 | (cons-stream 34 | (stream-car stream) 35 | (cons-stream 36 | (stream-car tail-of-stream) 37 | (cons-stream 38 | (stream-car (stream-cdr tail-of-stream)) 39 | (square-weight-filter (stream-cdr (stream-cdr tail-of-stream))))))) 40 | (square-weight-filter tail-of-stream)))) 41 | 42 | (define square-weight-numbers (square-weight-filter square-weighted-pairs)) 43 | (display-stream-head square-weight-numbers 100) 44 | -------------------------------------------------------------------------------- /3.5/e-3.77.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 3.77. The integral procedure used above was analogous to the 2 | ; ``implicit'' definition of the infinite stream of integers in section 3 | ; 3.5.2. Alternatively, we can give a definition of integral that is 4 | ; more like integers-starting-from (also in section 3.5.2): 5 | 6 | (define (integral integrand initial-value dt) 7 | (cons-stream initial-value 8 | (if (stream-null? integrand) 9 | the-empty-stream 10 | (integral (stream-cdr integrand) 11 | (+ (* dt (stream-car integrand)) 12 | initial-value) 13 | dt)))) 14 | 15 | ; When used in systems with loops, this procedure has the same problem 16 | ; as does our original version of integral. Modify the procedure so that 17 | ; it expects the integrand as a delayed argument and hence can be used 18 | ; in the solve procedure shown above. 19 | ; ------------------------------------------------------------ 20 | 21 | ; So if we expect delayed argument in the procedure then we have to 22 | ; force it to get its value and to delay it again when passing in 23 | ; recursion 24 | 25 | (define (integral delayed-integrand initial-value dt) 26 | (cons-stream initial-value 27 | (if (stream-null? (force delayed-integrand)) ; here forcing the evaluation 28 | the-empty-stream 29 | (integral (delay (stream-cdr (force delayed-integrand))) ; here delaying the tail again 30 | (+ (* dt (stream-car integrand)) 31 | initial-value) 32 | dt)))) 33 | -------------------------------------------------------------------------------- /2.5/e-2.86.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 2.86. 2 | ; 3 | ; Suppose we want to handle complex numbers whose real parts, 4 | ; imaginary parts, magnitudes, and angles can be either ordinary numbers, 5 | ; rational numbers, or other numbers we might wish to add to the system. 6 | ; Describe and implement the changes to the system needed to accommodate this. 7 | ; You will have to define operations such as sine and cosine that are generic 8 | ; over ordinary numbers and rational numbers. 9 | ;------------------------------------------------------------ 10 | 11 | ; First to see how things were defined 12 | (load "../helpers.scm") 13 | (load "arithmetics.scm") 14 | 15 | ; as example I will implement only the sine and cosine generic functions. Other primitive functions 16 | ; must be implemented in order tha whole system works with generic solutions. 17 | 18 | (define (sine x) (apply-generic 'sine x)) 19 | (define (cosine x) (apply-generic 'cosine x)) 20 | 21 | ;; add into scheme-number package 22 | (put 'sine '(scheme-number) (lambda (x) (sin x))) 23 | (put 'cosine '(scheme-number) (lambda (x) (cos x))) 24 | 25 | ;; add into rational package 26 | (put 'sine '(rational) (lambda (x) (attach-tag 'rational (sin (/ (car x) (cdr x)))))) 27 | (put 'cosine '(rational) (lambda (x) (attach-tag 'rational (cos (/ (car x) (cdr x)))))) 28 | 29 | (output (sine 3.14159265)) 30 | (output (sine (make-rational 4 2))) 31 | 32 | ; Instead of + and / we have to use generic add and div 33 | ; We would have to implement generic square, atan and to install them 34 | ; in packages. This is a bit over too much for this section if you do all the exercises. 35 | ; The goal is definitely reached by understanding all up to now :) 36 | -------------------------------------------------------------------------------- /2.2/e-2.49.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 2.49. Use segments->painter to define the following 2 | ; primitive painters: 3 | 4 | ; a. The painter that draws the outline of the designated frame. 5 | 6 | ; b. The painter that draws an ``X'' by connecting opposite corners of the frame. 7 | 8 | ; c. The painter that draws a diamond shape by connecting the midpoints of the sides of the frame. 9 | 10 | ; d. The wave painter. 11 | ; -------------------------------------------------------- 12 | 13 | ; I have to define list of segments that define the painters 14 | 15 | ; 1. outine of the frame 16 | 17 | (define outline-painter 18 | (define outline-segment-list 19 | (list 20 | (make-segment (make-vect 0 0) (make-vect 1 0)) 21 | (make-segment (make-vect 1 0) (make-vect 1 1)) 22 | (make-segment (make-vect 1 1) (make-vect 0 1)) 23 | (make-segment (make-vect 0 1) (make-vect 0 0)))) 24 | (segments->painteri outline-segment-list)) 25 | 26 | (define x-painter 27 | (define x-segment-list 28 | (list 29 | (make-segment (make-vect 0 0) (make-vect 1 1)) 30 | (make-segment (make-vect 0 1) (make-vect 1 0)))) 31 | (segments->painter x-segment-list)) 32 | 33 | (define diamond-painter 34 | (define diamond-segment-list 35 | (list 36 | (make-segment (make-vect 0.5 0) (make-vect 1 0.5)) 37 | (make-segment (make-vect 1 0.5) (make-vect 0.5 1)) 38 | (make-segment (make-vect 0.5 1) (make-vect 0 0.5)) 39 | (make-segment (make-vect 0 0.5) (make-vect 0.5 0)))) 40 | (segments->painter diamond-segment-list)) 41 | 42 | ; I don't do 4th since there is nothing to learn from doing it and I 43 | ; would need to define the points for every line ... 44 | 45 | 46 | -------------------------------------------------------------------------------- /4.1/e-4.17.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 4.17. 2 | ; 3 | ; Draw diagrams of the environment in 4 | ; effect when evaluating the expression in the 5 | ; procedure in the text, comparing how this will be 6 | ; structured when definitions are interpreted 7 | ; sequentially with how it will be structured if 8 | ; definitions are scanned out as described. Why is there 9 | ; an extra frame in the transformed program? Explain why 10 | ; this difference in environment structure can never make 11 | ; a difference in the behavior of a correct program. 12 | ; Design a way to make the interpreter implement the 13 | ; ``simultaneous'' scope rule for internal definitions 14 | ; without constructing the extra frame. 15 | ; ------------------------------------------------------------ 16 | 17 | (load "e-4.16.scm") 18 | 19 | ; Extra frame appears because applying let means doing an application 20 | ; of the ((lambda (t u) ()) t-val u-val) which constructs the environment. 21 | 22 | ; It is not making a difference because this is just one more wrapper local frame. 23 | ; 24 | ; if we, instead of scanning out the definitions, just put them on top, that will ensure 25 | ; that all of them are automatically defined in the environment once their application is 26 | ; issued. I can rewrite scan-out-defines 27 | 28 | (define (scan-out-defines body) 29 | (append (filter (lambda (element) (eq? (car element) 'define)) body) 30 | (filter (lambda (element) (not (eq? (car element) 'define))) body))) 31 | 32 | 33 | (define input '(lambda () 34 | (define t (+ 3 2)) 35 | (display "test") 36 | (define p (car (cons 1 2))))) 37 | 38 | ;(output (scan-out-defines (cddr input))) 39 | -------------------------------------------------------------------------------- /5.2/e-5.8.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 5.8. The following register-machine code is ambiguous, 2 | ; because the label here is defined more than once: 3 | 4 | start 5 | (goto (label here)) 6 | here 7 | (assign a (const 3)) 8 | (goto (label there)) 9 | here 10 | (assign a (const 4)) 11 | (goto (label there)) 12 | there 13 | 14 | ; With the simulator as written, what will the contents of register a be 15 | ; when control reaches there? Modify the extract-labels procedure so 16 | ; that the assembler will signal an error if the same label name is used 17 | ; to indicate two different locations. 18 | ; ------------------------------------------------------------ 19 | 20 | ; The way it is implemented, since we are consing the label list, last 21 | ; one will be always found first, so value of a will end up as being 4 22 | 23 | ; Adding a check if label is already in the list of pairs is easy. 24 | ; We just have to use (assoc) procedure for extracting the potential 25 | ; label and render error in that case. 26 | 27 | (define (extract-labels text receive) 28 | (if (null? text) 29 | (receive '() '()) 30 | (extract-labels (cdr text) 31 | (lambda (insts labels) 32 | (let ((next-inst (car text))) 33 | (if (symbol? next-inst) 34 | (if (assoc next-inst labels) ; adding a check if label already exists in the list 35 | (error "Multiple usage of the same label -- EXTRACT_LABELS" next-inst) 36 | (receive insts 37 | (cons (make-label-entry next-inst insts) 38 | labels))) 39 | (receive (cons (make-instruction next-inst) 40 | insts) 41 | labels))))))) 42 | -------------------------------------------------------------------------------- /3.5/e-3.71.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 3.71. 2 | ; 3 | ; Numbers that can be expressed as the sum of two cubes in more 4 | ; than one way are sometimes called Ramanujan numbers, in honor of the 5 | ; mathematician Srinivasa Ramanujan.70 Ordered streams of pairs provide an 6 | ; elegant solution to the problem of computing these numbers. To find a number 7 | ; that can be written as the sum of two cubes in two different ways, we need 8 | ; only generate the stream of pairs of integers (i,j) weighted according to the 9 | ; sum i3 + j3 (see exercise 3.70), then search the stream for two consecutive 10 | ; pairs with the same weight. Write a procedure to generate the Ramanujan 11 | ; numbers. The first such number is 1,729. What are the next five? 12 | 13 | (load "e-3.70.scm") 14 | 15 | (define (ramanujan-weight pair) 16 | (let ((i (car pair)) 17 | (j (cadr pair))) 18 | (+ (* i i i) (* j j j)))) 19 | 20 | (define ramanujan-weighted-pairs 21 | (weighted-pairs 22 | integers 23 | integers 24 | ramanujan-weight)) 25 | 26 | ; (display-stream-head (stream-map ramanujan-weight ramanujan-weighted-pairs) 100) 27 | 28 | (define (ramanujan-stream-filter stream) 29 | (let* ((weight1 (ramanujan-weight (stream-car stream))) 30 | (tail-of-stream (stream-cdr stream)) 31 | (weight2 (ramanujan-weight (stream-car tail-of-stream)))) 32 | (if (= weight1 weight2) 33 | (cons-stream weight1 (ramanujan-stream-filter (stream-cdr tail-of-stream))) 34 | (ramanujan-stream-filter tail-of-stream)))) 35 | 36 | (define ramanujan-numbers (ramanujan-stream-filter ramanujan-weighted-pairs)) 37 | (display-stream-head ramanujan-numbers 10) ;1729 4104 13832 20683 32832 39312 40033 46683 64232 65728 38 | 39 | -------------------------------------------------------------------------------- /3.1/e-3.4.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 3.4. Modify the make-account procedure of exercise 3.3 by 2 | ; adding another local state variable so that, if an account is accessed 3 | ; more than seven consecutive times with an incorrect password, it 4 | ; invokes the procedure call-the-cops. 5 | ; ------------------------------------------------------------ 6 | 7 | (load "../helpers.scm") 8 | 9 | (define (make-account balance account-password) 10 | (define (withdraw amount) 11 | (if (>= balance amount) 12 | (begin (set! balance (- balance amount)) 13 | balance) 14 | "Insufficient funds")) 15 | (define (deposit amount) 16 | (set! balance (+ balance amount)) 17 | balance) 18 | ; action dispatcher, protected by password 19 | (let ((attempts 0)) 20 | (lambda (password m) 21 | (if (eq? password account-password) 22 | (cond ((eq? m 'withdraw) withdraw) 23 | ((eq? m 'deposit) deposit) 24 | (else (error "Unknown request -- MAKE-ACCOUNT" m))) 25 | ; just return complaint, but has to accept argument 26 | (lambda (n) 27 | (set! attempts (+ attempts 1)) 28 | (if (>= attempts 7) 29 | "Lizard detected. Calling cops" 30 | "Incorrect password")))))) 31 | 32 | (define acc (make-account 100 'wizards!lizards)) 33 | (output ((acc 'wizards!lizards 'withdraw) 40)) 34 | (output ((acc 'lizards!wizards 'withdraw) 40)) 35 | (output ((acc 'lizards!wizards 'withdraw) 40)) 36 | (output ((acc 'lizards!wizards 'withdraw) 40)) 37 | (output ((acc 'lizards!wizards 'withdraw) 40)) 38 | (output ((acc 'lizards!wizards 'withdraw) 40)) 39 | (output ((acc 'lizards!wizards 'withdraw) 40)) 40 | (output ((acc 'lizards!wizards 'withdraw) 40)) 41 | -------------------------------------------------------------------------------- /3.4/e-3.38.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 3.38. Suppose that Peter, Paul, and Mary share a joint bank 2 | ; account that initially contains $100. Concurrently, Peter deposits 3 | ; $10, Paul withdraws $20, and Mary withdraws half the money in the 4 | ; account, by executing the following commands: 5 | 6 | ; Peter: (set! balance (+ balance 10)) 7 | ; Paul: (set! balance (- balance 20)) 8 | ; Mary: (set! balance (- balance (/ balance 2))) 9 | 10 | ; a. List all the different possible values for balance after these 11 | ; three transactions have been completed, assuming that the banking 12 | ; system forces the three processes to run sequentially in some order. 13 | 14 | ; b. What are some other values that could be produced if the system 15 | ; allows the processes to be interleaved? Draw timing diagrams like the 16 | ; one in figure 3.29 to explain how these values can occur. 17 | ; ------------------------------------------------------------ 18 | 19 | ; a) These events can occur in any order, so we have number of 20 | ; permutations of the set to evaluate. Lets say we have three events 21 | ; Pe, Pa and Ma. All permutations in which they can appear are 22 | ; 23 | ; balance = 100 initially 24 | ; Pe = +10 25 | ; Pa = -20 26 | ; Ma = /2 27 | ; 28 | ; (Pe, Pa, Ma) => ((100 + 10) - 20) / 2 = 45 29 | ; (Pe, Ma, Pa) => ((100 + 10) / 2) - 20 = 35 30 | ; (Pa, Pe, Ma) => ((100 - 20) + 10) / 2 = 45 31 | ; (Pa, Ma, Pe) => ((100 - 20) / 2) + 10 = 50 32 | ; (Ma, Pa, Pe) => 100/2 -20 + 10 = 40 33 | ; (Ma, Pe, Pa) => 100/2 + 10 - 20 = 40 34 | ; 35 | ; b) Here we have complex situation of three process which all have 36 | ; (set!) procedure application that executes in several steps, with all 37 | ; the permutatations we an draw some diagrams easily. 38 | -------------------------------------------------------------------------------- /3.4/e-3.46.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 3.46. 2 | ; 3 | ; Suppose that we implement test-and-set! using an 4 | ; ordinary procedure as shown in the text, without attempting to make 5 | ; the operation atomic. Draw a timing diagram like the one in figure 6 | ; 3.29 to demonstrate how the mutex implementation can fail by allowing 7 | ; two processes to acquire the mutex at the same time. 8 | ; ------------------------------------------------------------ 9 | 10 | ; First we have to define what means to aquire mutex. 11 | ; In the implementation of make-mutex and test-and-set! state of 12 | ; waiting for mutex to be aquired is defined by recursive call to 13 | ; (mutex 'aquire) until it retuns false. 14 | ; So, we are looking for the case in which both of them are going to 15 | ; return false from the (test-and-set!) and procede with execution. 16 | 17 | ; So, if test-and-set! is not atomic, both processes can do check for 18 | ; the (if (car cell)) one after the other without waiting for each other 19 | ; to set it. After that case we'll have that both of the processes are 20 | ; going to understand that they will exclusively acquire the mutex which 21 | ; is not true. 22 | 23 | 24 | 25 | ; time 26 | ; || P1 P2 27 | ; || | | 28 | ; || (if (car cell)) | 29 | ; || | | 30 | ; || | (if (car cell)) 31 | ; || | | 32 | ; || | | 33 | ; || acquire it | 34 | ; || | 35 | ; || acquire it 36 | ; || 37 | ; || 38 | ; \ / 39 | ; \/ 40 | -------------------------------------------------------------------------------- /5.1/notes.md: -------------------------------------------------------------------------------- 1 | # Register machines 2 | 3 | Two basic concepts in the topic of register machines are `data paths` 4 | that are registers and operations and `controller` which represents 5 | sequence in which these operations are executed. 6 | 7 | ## Language for describing register machines 8 | 9 | In order to effectively describe the register machine, we will introduce a 10 | language specialized for this purpose. 11 | 12 | Controller of the register machine is defined as a sequence of 13 | `instructions` together with set of `labels` that identify some 14 | significant entry points in the sequence. 15 | 16 | Instruction can be one of these: 17 | 18 | * assignment of value to the register (`assign` instruction) 19 | * test instruction for testing the state of certain register (`test` 20 | instruction) 21 | * conditional branching (`branch` instruction) of controller execution path based on the outcome 22 | of the given test instruction. 23 | * Unconditional branch (`goto` instruction) 24 | 25 | ## Stack 26 | 27 | When we introduced procedural abstraction in some of the first chapters, we introduced the notion of procedure which contains a list of steps to be executed when it was called. In that moment we did'nt care about how program knows how to come back to the position where it called the procedure and how to return the output of the computation to the calling procedure. 28 | 29 | Now, seeing how register machine works, we see a need for some place 30 | where `state` of the controller will be saved and restored from when we 31 | enter exection of the subroutine. This place where state is saved we 32 | will call `stack`. Stack is "last-in first-out" data structure. And data 33 | gets on the stack by being `saved` and taken out when `restored`. 34 | -------------------------------------------------------------------------------- /2.5/e-2.87.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 2.87. 2 | ; 3 | ; Install =zero? for polynomials in the generic 4 | ; arithmetic package. This will allow adjoin-term to work for 5 | ; polynomials with coefficients that are themselves polynomials. 6 | ; ------------------------------------------------------------ 7 | 8 | (load "../helpers.scm") 9 | (load "arithmetics.scm") 10 | (load "symbolic_algebra.scm") 11 | 12 | ; polynoial is zero if all terms are zeor, we can cdr down the term list 13 | ; to check all the terms 14 | 15 | (define (update-polynomial-package) 16 | (define (variable p) (car p)) 17 | (define (term-list p) (cdr p)) 18 | (define (variable? x) (symbol? x)) 19 | (define (same-variable? v1 v2) 20 | (and (variable? v1) (variable? v2) (eq? v1 v2))) 21 | (define (adjoin-term term term-list) 22 | (if (=zero? (coeff term)) 23 | term-list 24 | (cons term term-list))) 25 | (define (the-empty-termlist) '()) 26 | (define (first-term term-list) (car term-list)) 27 | (define (rest-terms term-list) (cdr term-list)) 28 | (define (empty-termlist? term-list) (null? term-list)) 29 | (define (make-term order coeff) (list order coeff)) 30 | (define (order term) (car term)) 31 | (define (coeff term) (cadr term)) 32 | 33 | (define (zero-poly? poly) 34 | (define (zero-terms? termlist) 35 | (if (empty-termlist? termlist) 36 | '#t 37 | (and (=zero? (coeff (first-term termlist))) 38 | (zero-terms? (rest-terms termlist))))) 39 | (zero-terms? (term-list poly))) 40 | (put '=zero? '(polynomial) zero-poly?)) 41 | 42 | (update-polynomial-package) 43 | 44 | (output (=zero? (make-polynomial 'x (list (list 1 0) (list 0 0)) ))) ; #t 45 | (output (=zero? (make-polynomial 'x (list (list 1 0) (list 0 1)) ))) ; #f 46 | -------------------------------------------------------------------------------- /2.5/e-2.83.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 2.83. 2 | ; 3 | ; Suppose you are designing a generic arithmetic 4 | ; system for dealing with the tower of types shown in figure 2.25: 5 | ; integer, rational, real, complex. For each type (except 6 | ; complex), design a procedure that raises objects of that type 7 | ; one level in the tower. Show how to install a generic raise 8 | ; operation that will work for each type (except complex). 9 | ; ------------------------------------------------------------ 10 | 11 | (load "../helpers.scm") 12 | (load "2.5.scm") 13 | (load "e-2.78.scm") 14 | 15 | (define (raise-scheme-number n) 16 | (make-rational n 1)) 17 | 18 | ;; internal procedures 19 | (define (numer x) (car x)) 20 | (define (denom x) (cdr x)) 21 | 22 | (define (raise-rational n) 23 | (attach-tag 'real (/ (numer (content n)) (denom (content n))))) 24 | 25 | (define (raise-real n) 26 | (make-complex-from-mag-ang (content n) 0)) 27 | 28 | ; test procedures to how raise works 29 | ; (output (raise-scheme-number 5)) 30 | ; (output (raise-rational (make-rational 3 2))) 31 | ; (output (raise-real (raise-rational (make-rational 3 2)))) 32 | 33 | 34 | ; here we can define generic raise procedure for our 35 | ; arithmetic system and install it 36 | 37 | (define (update-scheme-number-package) 38 | (put 'raise '(scheme-number) raise-scheme-number)) 39 | 40 | (update-scheme-number-package) 41 | 42 | (define (raise-rational-to-complex n) 43 | (make-complex-from-real-imag (/ (numer n) (denom n)) 0)) 44 | 45 | 46 | ; since we dont work with real numbers yet 47 | (define (update-rational-package) 48 | (put 'raise '(rational) raise-rational-to-complex)) 49 | 50 | (update-rational-package) 51 | 52 | (define (raise n) (apply-generic 'raise n)) 53 | 54 | ; (output (raise 5)) 55 | -------------------------------------------------------------------------------- /4.1/e-4.7.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 4.7. Let* is similar to let, except that the bindings of the let 2 | ; variables are performed sequentially from left to right, and each binding is 3 | ; made in an environment in which all of the preceding bindings are visible. 4 | ; For example 5 | 6 | ; (let* ((x 3) 7 | ; (y (+ x 2)) 8 | ; (z (+ x y 5))) 9 | ; (* x z)) 10 | 11 | ; returns 39. Explain how a let* expression can be rewritten as a set of nested 12 | ; let expressions, and write a procedure let*->nested-lets that performs this 13 | ; transformation. If we have already implemented let (exercise 4.6) and we want 14 | ; to extend the evaluator to handle let*, is it sufficient to add a clause to 15 | ; eval whose action is 16 | 17 | ; (eval (let*->nested-lets exp) env) 18 | 19 | ; or must we explicitly expand let* in terms of non-derived expressions? 20 | ; ------------------------------------------------------------ 21 | 22 | (load "../helpers.scm") 23 | (load "e-4.6.scm") 24 | 25 | (define (let*->nested-lets exp) 26 | (expand-let* (cadr exp) (caddr exp))) 27 | 28 | (define (expand-let* bindings body) 29 | (if (null? (cdr bindings)) 30 | (make-let (car bindings) body) 31 | (make-let (car bindings) (expand-let* (cdr bindings) body)))) 32 | 33 | (define (make-let bindings body) 34 | (list 'let (list bindings) body)) 35 | 36 | (output (let*->nested-lets '(let* ((x 3) (y (+ x 2)) (z (+ x y 5))) (* x z)))) 37 | ; outputs (let ((x 3)) (let ((y (+ x 2))) (let ((z (+ x y 5))) (* x z)))) 38 | 39 | ; I think using it as (eval (let*->nested-lets exp) env) should be safe 40 | ; because lets are transformed to application of (lambdas) which evaluate with changing the 41 | ; environments as needed, so setting new variable in the environment would be as expected 42 | -------------------------------------------------------------------------------- /3.3/e-3.35.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 3.35. Ben Bitdiddle tells Louis that one way to avoid the 2 | ; trouble in exercise 3.34 is to define a squarer as a new primitive 3 | ; constraint. Fill in the missing portions in Ben's outline for a 4 | ; procedure to implement such a constraint: 5 | 6 | ; (define (squarer a b) 7 | ; (define (process-new-value) 8 | ; (if (has-value? b) 9 | ; (if (< (get-value b) 0) 10 | ; (error "square less than 0 -- SQUARER" (get-value b)) 11 | ; ) 12 | ; )) 13 | ; (define (process-forget-value) ) 14 | ; (define (me request) ) 15 | ; 16 | ; me) 17 | ; ------------------------------------------------------------ 18 | 19 | (load "../helpers.scm") 20 | (load "constraints.scm") 21 | 22 | (define (squarer a b) 23 | (define (process-new-value) 24 | (if (has-value? b) 25 | (if (< (get-value b) 0) 26 | (error "square less than 0 -- SQUARER" (get-value b)) 27 | (set-value! a (sqrt (get-value b)) me)) 28 | (if (has-value? a) 29 | (set-value! b (* (get-value a) (get-value a)) me)))) 30 | 31 | (define (process-forget-value) 32 | (forget-value! a me) 33 | (forget-value! b me) 34 | (process-new-value)) 35 | 36 | (define (me request) 37 | (cond ((eq? request 'I-have-a-value) (process-new-value)) 38 | ((eq? request 'I-lost-my-value) (process-forget-value)))) 39 | 40 | (connect a me) 41 | (connect b me) 42 | me) 43 | 44 | (define a (make-connector)) 45 | (define b (make-connector)) 46 | (squarer a b) 47 | 48 | (set-value! a 100 'ivan) 49 | (forget-value! a 'ivan) 50 | (set-value! a 10 'ivan) 51 | (output (get-value b)) 52 | (output (get-value a)) ; outputs #f which is wrong 53 | -------------------------------------------------------------------------------- /2.2/e-2.41.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 2.41. 2 | ; 3 | ; Write a procedure to find all ordered triples of distinct positive integers i, j, and k 4 | ; less than or equal to a given integer n that sum to a given integer s. 5 | ; -------------------------------------------- 6 | 7 | (load "../common.scm") 8 | (load "../helpers.scm") 9 | (load "2.2.scm") 10 | 11 | ; First we have to create generator of the list of triples, which is 12 | ; just one more level of nesting than with 2 levels. 13 | ; 14 | ; This can be probably abstracted to a method that can build 15 | ; recursively any level of nesting. If needed I'll do it later' 16 | (define (unique-triples n) 17 | (flatmap (lambda (i) 18 | (map (lambda (jk-pair) (append jk-pair (list i))) 19 | (flatmap (lambda (j) 20 | (map (lambda (k) (list k j)) 21 | (enumerate-interval 1 (- j 1)))) 22 | (enumerate-interval 1 (- i 1))))) 23 | (enumerate-interval 1 n))) 24 | 25 | ; helper method to easily get the sum of the triplet 26 | (define (triplet-sum triplet) 27 | (+ (car triplet) (cadr triplet) (cadr (cdr triplet)))) 28 | 29 | ; append sum to triplet 30 | (define (make-triplet-sum triplet) 31 | (append triplet (list (triplet-sum triplet)))) 32 | 33 | ; generate filter method that is in fact closure with given s as 34 | ; the enclosed value 35 | (define (triplet-sum-equal? s) 36 | (lambda (triplet) (= (triplet-sum triplet) s))) 37 | 38 | ; using the flow of the data to filter out what I need and generate 39 | ; proper presentationat the end 40 | (define (sum-equal-triplets n s) 41 | (map make-triplet-sum 42 | (filter (triplet-sum-equal? s) 43 | (unique-triples n)))) 44 | 45 | (output (sum-equal-triplets 5 10)) 46 | -------------------------------------------------------------------------------- /4.1/e-4.18.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 4.18. Consider an alternative strategy for scanning out definitions 2 | ; that translates the example in the text to 3 | 4 | (lambda 5 | (let ((u '*unassigned*) 6 | (v '*unassigned*)) 7 | (let ((a ) 8 | (b )) 9 | (set! u a) 10 | (set! v b)) 11 | )) 12 | 13 | ; Here a and b are meant to represent new variable names, created by the 14 | ; interpreter, that do not appear in the user's program. Consider the solve 15 | ; procedure from section 3.5.4: 16 | 17 | (define (solve f y0 dt) 18 | (define y (integral (delay dy) y0 dt)) 19 | (define dy (stream-map f y)) 20 | y) 21 | 22 | ; Will this procedure work if internal definitions are scanned out as shown in 23 | ; this exercise? What if they are scanned out as shown in the text? Explain. 24 | ; ------------------------------------------------------------ 25 | 26 | ; In order to see how this behaves, we have to evaluate it to the primitive procedures 27 | 28 | (define (solve f y0 dt) 29 | (define y (integral (delay dy) y0 dt)) 30 | (define dy (stream-map f y)) 31 | y) 32 | 33 | ;becomes by our exercise 34 | (define (solve f y0 dt) 35 | (let ((y '*unassigned*) 36 | (dy '*unassigned*)) 37 | (let ((a (integral (delay dy) y0 dt)) 38 | (b (stream-map f y))) 39 | (set! y a) 40 | (set! dy b)) 41 | y)) 42 | 43 | ; which, after expanding inner let to primitive lambda application 44 | (define (solve f y0 dt) 45 | (let ((y '*unassigned*) 46 | (dy '*unassigned*)) 47 | ((lambda (a b) 48 | (set! y a) 49 | (set dy b)) 50 | (integral (delay dy) y0 dt) 51 | (stream-map f y)) 52 | y)) 53 | 54 | ; In this form, in order to assign values to a and b value of y is tried 55 | ; to be evaluated but it is still not assigned 56 | -------------------------------------------------------------------------------- /4.1/e-4.9.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 4.9. 2 | ; 3 | ; Many languages support a variety of iteration 4 | ; constructs, such as do, for, while, and until. In Scheme, 5 | ; iterative processes can be expressed in terms of ordinary 6 | ; procedure calls, so special iteration constructs provide no 7 | ; essential gain in computational power. On the other hand, such 8 | ; constructs are often convenient. Design some iteration 9 | ; constructs, give examples of their use, and show how to 10 | ; implement them as derived expressions. 11 | ; ------------------------------------------------------------ 12 | 13 | (load "../helpers.scm") 14 | (load "4.1.scm") 15 | 16 | ; I'll take while construct as example 17 | ; 18 | ; (while 19 | ; ) 20 | ; 21 | ; 22 | 23 | ; example of use 24 | 25 | ; (define counter 5) 26 | ; (while (> counter 0) 27 | ; (set! counter (- counter 1)) 28 | ; (display counter)) ; or any other body sequence 29 | ; 30 | ; It can be expanded as combination 31 | ; 32 | ; ((define iter 33 | ; (if test 34 | ; (begin 35 | ; body 36 | ; iter))) 37 | ; iter) 38 | 39 | ; (define eval exp env 40 | ; ... 41 | ; (while? exp) (eval (while->combination exp) env) 42 | ; ...) 43 | 44 | (define (while? exp) 45 | (eq? (car exp) 'while)) 46 | 47 | (define (while->combination exp) 48 | (expand-while (cdr exp))) 49 | 50 | (define (expand-while operands) 51 | (list 52 | (make-define 'iter '() 53 | (list (make-if (car operands) 54 | (list 'begin 55 | (cadr operands) 56 | (list 'iter)) 57 | '()))) 58 | (list 'iter))) 59 | 60 | 61 | ; This can be done with named let as well but that is already 62 | ; a derived construct 63 | 64 | (output (while->combination '(while (> counter 5) (display counter)))) 65 | -------------------------------------------------------------------------------- /3.5/e-3.75.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 3.75. 2 | ; 3 | ; Unfortunately, Alyssa's zero-crossing detector in 4 | ; exercise 3.74 proves to be insufficient, because the noisy signal from 5 | ; the sensor leads to spurious zero crossings. Lem E. Tweakit, a 6 | ; hardware specialist, suggests that Alyssa smooth the signal to filter 7 | ; out the noise before extracting the zero crossings. Alyssa takes his 8 | ; advice and decides to extract the zero crossings from the signal 9 | ; constructed by averaging each value of the sense data with the 10 | ; previous value. She explains the problem to her assistant, Louis 11 | ; Reasoner, who attempts to implement the idea, altering Alyssa's 12 | ; program as follows: 13 | 14 | (define (make-zero-crossings input-stream last-value) 15 | (let ((avpt (/ (+ (stream-car input-stream) last-value) 2))) 16 | (cons-stream (sign-change-detector avpt last-value) 17 | (make-zero-crossings (stream-cdr input-stream) 18 | avpt)))) 19 | 20 | ; This does not correctly implement Alyssa's plan. Find the bug that 21 | ; Louis has installed and fix it without changing the structure of the 22 | ; program. (Hint: You will need to increase the number of arguments to 23 | ; make-zero-crossings.) 24 | ; ------------------------------------------------------------ 25 | 26 | ; we have to pass both last value and last average for this approach to 27 | ; work 28 | (define (make-zero-crossings input-stream last-value last-average) 29 | (let* ((average (/ (+ current-value last-value) 2)) 30 | (current-value (stream-car input-stream))) 31 | (cons-stream (sign-change-detector average last-average) 32 | (make-zero-crossings (stream-cdr input-stream) 33 | current-value 34 | average)))) 35 | 36 | -------------------------------------------------------------------------------- /2.5/e-2.79.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 2.79. 2 | ; 3 | ; Define a generic equality predicate equ? that tests the 4 | ; equality of two numbers, and install it in the generic arithmetic package. 5 | ; This operation should work for ordinary numbers, rational numbers, and 6 | ; complex numbers. 7 | ; ------------------------------------------------------------ 8 | 9 | (load "2.5.scm") 10 | (load "e-2.78.scm") ; to use normal scheme numbers instead of typed 11 | 12 | 13 | ; This is one case where we have to add a generic procedure that affects all implementations. 14 | ; First we have to put the way we will call it, and then the way particular type of number 15 | ; will interpret it. 16 | 17 | (define (equ? x y) (apply-generic 'equ? x y)) 18 | 19 | ; and we have to tell which procedure should be used for the particular number type. 20 | ; We will make update procedures for every package 21 | (define (update-scheme-number-package) 22 | (put 'equ? '(scheme-number scheme-number) equal?)) 23 | 24 | (update-scheme-number-package) 25 | 26 | ; this needs access to internal procedures of the package which is 27 | ; different story 28 | (define (update-rational-package) 29 | (put 'equ? '(rational rational) 30 | (lambda (x y) (and (equal? (car x) (car y)) 31 | (equal? (cdr x) (cdr y)))))) 32 | 33 | (update-rational-package) 34 | 35 | (define (update-complex-package) 36 | (put 'equ? '(complex complex) 37 | (lambda (c1 c2) (and (equal? (real-part c1) (real-part c2)) 38 | (equal? (imag-part c1) (imag-part c2)))))) 39 | 40 | (update-complex-package) 41 | 42 | ; now some tests 43 | (output 44 | (equ? (make-complex-from-real-imag 3 4) 45 | (make-complex-from-real-imag 3 4))) 46 | 47 | (output 48 | (equ? (make-rational 3 4) 49 | (make-rational 3 4))) 50 | 51 | (output 52 | (equ? 5 5)) 53 | -------------------------------------------------------------------------------- /3.4/e-3.42.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 3.42. Ben Bitdiddle suggests that it's a waste of time to create a 2 | ; new serialized procedure in response to every withdraw and deposit message. 3 | ; He says that make-account could be changed so that the calls to protected are 4 | ; done outside the dispatch procedure. That is, an account would return the 5 | ; same serialized procedure (which was created at the same time as the account) 6 | ; each time it is asked for a withdrawal procedure. 7 | 8 | (define (make-account balance) 9 | (define (withdraw amount) 10 | (if (>= balance amount) 11 | (begin (set! balance (- balance amount)) 12 | balance) 13 | "Insufficient funds")) 14 | (define (deposit amount) 15 | (set! balance (+ balance amount)) 16 | balance) 17 | (let ((protected (make-serializer))) 18 | (let ((protected-withdraw (protected withdraw)) 19 | (protected-deposit (protected deposit))) 20 | (define (dispatch m) 21 | (cond ((eq? m 'withdraw) protected-withdraw) 22 | ((eq? m 'deposit) protected-deposit) 23 | ((eq? m 'balance) balance) 24 | (else (error "Unknown request -- MAKE-ACCOUNT" 25 | m)))) 26 | dispatch))) 27 | 28 | ; Is this a safe change to make? In particular, is there any difference in what 29 | ; concurrency is allowed by these two versions of make-account ? 30 | ; ------------------------------------------------------------ 31 | 32 | ; Difference is that in the previous case we had for every call 33 | ; ((account 'withdraw) 50) new protected procedure to execute 34 | ; 35 | ; In the case of this example we have always the same procedure execution. 36 | ; Both of these are local to this account object and they are safe to be 37 | ; this way since they will anyway share same synchronization primitive I guess. 38 | -------------------------------------------------------------------------------- /4.2/e-4.27.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 4.27. Suppose we type in the following definitions to the 2 | ; lazy evaluator: 3 | 4 | (define count 0) 5 | (define (id x) 6 | (set! count (+ count 1)) 7 | x) 8 | 9 | ; Give the missing values in the following sequence of interactions, and 10 | ; explain your answers.38 11 | 12 | (define w (id (id 10))) 13 | ;;; L-Eval input: 14 | count 15 | ;;; L-Eval value: 16 | 17 | ;;; L-Eval input: 18 | w 19 | ;;; L-Eval value: 20 | 21 | ;;; L-Eval input: 22 | count 23 | ;;; L-Eval value: 24 | 25 | ;------------------------------------------------------------ 26 | 27 | ; Responses are sequentially 28 | ; count -> 1 29 | ; w -> 10 30 | ; count -> 2 31 | 32 | ; The way id procedure is defined it will increment count by one 33 | ; and return the passed argument. 34 | ; 35 | ; During definition of the w, first call to apply id is evaluated as 36 | ; application, but internal one is not applied but is wrapped into thunk 37 | ; which is passed to outter call to id. 38 | ; So, after definition of the w, the value of w is the thunk created 39 | ; from (id 10) and outer id is evaluated which increased count for 1. 40 | ; 41 | ; Once w is asked for the actual value, it evaluates the thunk and 42 | ; returns 10, and increases count once more. That is why count goes to 43 | ; 2 after w is evaluated. 44 | ; 45 | ; If we evaluate w several more times, we can see that there is no 46 | ; increase of count anymore. That is because we have memoized the 47 | ; evaluation of the actual value of the thunk and therefore every next 48 | ; time only the value is returned without the evaluation of (id 10) 49 | ; which would increase the count every time. 50 | ; 51 | ; So, here we see the behavior of normal order evaluation, it applies 52 | ; procedure but doesn't evaluate its arguments until that is done 53 | ; intentionally. 54 | -------------------------------------------------------------------------------- /3.5/e-3.60.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 3.60. 2 | ; 3 | ; With power series represented as streams of 4 | ; coefficients as in exercise 3.59, adding series is implemented by 5 | ; add-streams. Complete the definition of the following procedure for 6 | ; multiplying series: 7 | 8 | ; (define (mul-series s1 s2) 9 | ; (cons-stream (add-streams ))) 10 | 11 | ; You can test your procedure by verifying that sin^2(x) + cos^2(x) = 1, 12 | ; using the series from exercise 3.59. 13 | ; ------------------------------------------------------------ 14 | 15 | (load "../helpers.scm") 16 | (load "3.5.scm") 17 | (load "e-3.59.scm") 18 | 19 | ; Since series is defined by the list of coefficients, mutiplying them 20 | ; is multiplying two multi coefficient sums. 21 | ; (a0 a1 a2 a3 ...) and (b0 b1 b2 b3 ...) 22 | ; 23 | ; If we represent it in the real sum form 24 | ; (a0 + a1*x + a2*x^2 + a3*x^3 + ...) * (b0 + b1*x + b2*x^2 + b3*x^3 + ...) 25 | ; that gives 26 | ; a0*b0 + a0*(b1*x + b2*x^2 + b3*x^3 + ...) + b0*(a1*x + a2*x^2 + a3*x^3 + ...) + ... 27 | ; 28 | ; more intuitive, if we define series as 29 | ; s1 = (a0 + Arest) and s2 = (b0 + Brest) then 30 | ; s1 * s2 = a0*b0 + a0*Brest + b0*Arest + Arest*Brest ... 31 | ; 32 | ; This is written as 33 | (define (mul-series s1 s2) 34 | (cons-stream 35 | (* (stream-car s1) (stream-car s2)) 36 | (add-streams 37 | (add-streams (scale-stream (stream-cdr s1) 38 | (stream-car s2)) 39 | (scale-stream (stream-cdr s2) 40 | (stream-car s1))) 41 | (cons-stream 0 (mul-series (stream-cdr s1) 42 | (stream-cdr s2)))))) 43 | 44 | (define circle (add-streams (mul-series sin-series sin-series) 45 | (mul-series cos-series cos-series))) 46 | 47 | ; (display-stream-head circle 10) ; 1 0 0 0 ... 48 | -------------------------------------------------------------------------------- /2.1/e-2.6.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 2.6. 2 | ; 3 | ; In case representing pairs as procedures wasn't mind-boggling enough, consider that, 4 | ; in a language that can manipulate procedures, we can get by without numbers (at least insofar 5 | ; as nonnegative integers are concerned) by implementing 0 and the operation of adding 1 as 6 | 7 | (define zero (lambda (f) (lambda (x) x))) 8 | 9 | (define (add-1 n) 10 | (lambda (f) (lambda (x) (f ((n f) x))))) 11 | 12 | ; This representation is known as Church numerals, after its inventor, Alonzo Church, 13 | ; the logician who invented the lambda calculus. 14 | ; 15 | ; Define one and two directly (not in terms of zero and add-1). 16 | ; (Hint: Use substitution to evaluate (add-1 zero)). Give a direct definition of the 17 | ; addition procedure + (not in terms of repeated application of add-1). 18 | ; ---------------------------------------------------------------- 19 | 20 | ; 1. Lets evaluate (add-1 zero) so we can see how one as CL looks like 21 | ; 22 | ; (add-1 zero) 23 | ; (add-1 (lambda (f) (lamda (x) x))) ; first evaluate operand 24 | ; ((lambda (f) (lambda (x) (f ((zero f) x))))) ; now apply the operator 25 | ; ((lambda (f) (lambda (x) (f (((lambda (f) (lambda (x) x)) f) x))))) ; reduces to 26 | ; ((lambda (f) (lambda (x) (f ((lambda (x) x) x))))) ; reduces to 27 | ; (lambda (f) (lambda (x) (f x))) 28 | 29 | ; Finally we can define numeral 1 as compound procedure. 30 | ; It is in fact the same as defined in 31 | ; http://en.wikipedia.org/wiki/Church_encoding#Church_numerals 32 | (define one 33 | (lambda (f) (lambda (x) (f x)))) 34 | 35 | ; without doing substitution again I can define two as 36 | (define two 37 | (lambda (f) (lambda (x) (f (f x))))) 38 | 39 | 40 | ; addition n + m is defined by f^n(f^m(x)) so I just have to define it 41 | ; as such 42 | 43 | (define (add m n) 44 | (lambda (f) (lambda (x) ((m f) ((n f) x))))) 45 | -------------------------------------------------------------------------------- /2.2/e-2.51.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 2.51. 2 | ; 3 | ; Define the below operation for painters. Below takes 4 | ; two painters as arguments. The resulting painter, given a frame, draws 5 | ; with the first painter in the bottom of the frame and with the second 6 | ; painter in the top. Define below in two different ways -- first by 7 | ; writing a procedure that is analogous to the beside procedure given 8 | ; above, and again in terms of beside and suitable rotation operations 9 | ; (from exercise 2.50). 10 | ; -------------------------------------------------- 11 | 12 | ; first the same way beside does it by splitting into two 13 | ; frames and returning composing function that will render both 14 | (define (below painter1 painter2) 15 | (let ((split-point (make-vect 0.0 0.5))) 16 | (let ((paint-bottom 17 | (transform-painter painter1 18 | (make-vect 0.0 0.0) 19 | split-point 20 | (make-vect 1.0 .0.0))) 21 | (paint-top 22 | (transform-painter painter2 23 | split-point 24 | (make-vect 0.0 1.0) 25 | (make-vect 0.5 1.0))))) 26 | (lambda (frame) 27 | (paint-bottom frame) 28 | (paint-top frame)))) 29 | 30 | ; the other way is to reuse beside and just rotate it first 180 and then 31 | ; additional 270, that way we'll get 450 degrees of rotation which is 90 32 | ; degrees real, and that will make it one below eachother. Before that 33 | ; we have to rotate each individual painter so they are positioned 34 | ; properly at the end. We could have defined as well transformation of 35 | ; 90 degrees ... 36 | (define (below painter1 painter2) 37 | (rotate-270-cc 38 | (rotate-180-cc 39 | (beside (rotate-270-cc painter1) (rotate-270-cc painter2))))) 40 | -------------------------------------------------------------------------------- /5.1/e-5.4.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 5.4. Specify register machines that implement each of the 2 | ; following procedures. For each machine, write a controller instruction 3 | ; sequence and draw a diagram showing the data paths. 4 | 5 | ; a. Recursive exponentiation: 6 | 7 | (define (expt b n) 8 | (if (= n 0) 9 | 1 10 | (* b (expt b (- n 1))))) 11 | 12 | ; b. Iterative exponentiation: 13 | 14 | (define (expt b n) 15 | (define (expt-iter counter product) 16 | (if (= counter 0) 17 | product 18 | (expt-iter (- counter 1) (* b product)))) 19 | (expt-iter n 1)) 20 | ; ------------------------------------------------------------ 21 | 22 | ; I will just define the machines. 23 | 24 | ; a) based n already given implementation in 5.1.scm we can similarly 25 | ; implement exponential. 26 | 27 | (controller 28 | (assign continue (label expt-done)) 29 | expt-loop 30 | (test (op =) (reg n) (const 0)) 31 | (branch (label base-case)) 32 | ; save current state and continue at after-expt 33 | (save continue) 34 | (save n) 35 | (assign n (op -) (reg n) (const 1)) 36 | (assign continue (label after-fact)) 37 | (goto (label expt-loop)) 38 | after-expt 39 | (restore n) 40 | (restore continue) 41 | (assign val (op *) (reg b) (reg val)) 42 | (goto (reg continue)) 43 | base-case 44 | (assign val (const 1)) 45 | (goto (reg continue)) 46 | expt-done) 47 | 48 | ; b) This is similar to the iterative machines we have already defined 49 | ; before. 50 | 51 | (controller 52 | init 53 | (assign counter (read)) ; assuming read is a primitive 54 | (assign base (read)) 55 | (assign product (const 1)) 56 | expt-iter 57 | (test (op =) (reg counter) (const 0)) 58 | (branch (label expt-done)) 59 | (assign counter (op -) (reg counter) (const 1)) 60 | (assign product (op *) (reg base) (reg product)) 61 | (goto expt-iter) 62 | expt-done) 63 | -------------------------------------------------------------------------------- /1.3/e-1.31.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 1.31 2 | ; 3 | ; a. The sum procedure is only the simplest of a vast number of similar abstractions 4 | ; that can be captured as higher-order procedures. Write an analogous procedure 5 | ; called product that returns the product of the values of a function at points over 6 | ; a given range. Show how to define factorial in terms of product. Also use product 7 | ; to compute approximations to value of pi using the formula. 8 | ; 9 | ; pi 2 * 4 * 4 * 6 * 6 * 8 ... 10 | ; -- = ------------------------- 11 | ; 4 3 * 3 * 5 * 5 * 7 * 7 ... 12 | ; 13 | ; b. If your product procedure generates a recursive process, write one that generates 14 | ; an iterative process. If it generates an iterative process, write one that generates 15 | ; a recursive process. 16 | ; 17 | ; ---------------------------------------------------------------------------------- 18 | ; 19 | 20 | (load "../common.scm") 21 | 22 | ; definition of the product 23 | (define (product term a next b) 24 | (if (> a b) 25 | 1 26 | (* 27 | (term a) 28 | (product term (next a) next b)))) 29 | 30 | (define (fact n) 31 | (define (identity x) x) 32 | (define (next x) (+ x 1)) 33 | (product identity 1 next n)) 34 | 35 | ; (display (fact 10)) ; 3628800 36 | ; (newline) 37 | 38 | (define (pi n) 39 | (define (next x) (+ x 2)) 40 | (* 4.0 (/ (* 2 (product square 4 next (- n 2)) n ) (product square 3 next n)))) 41 | 42 | ; (display (pi 400)) ; approximates to 3.14 43 | ; (newline) 44 | 45 | ; iterative process definition 46 | (define (product term a next b) 47 | (define (iter a result) 48 | (if (> a b) 49 | result 50 | (iter (next a) (* result (term a))))) 51 | (iter a 1)) 52 | 53 | ; Now we can execute approximation of pi with better precision since we use less memory 54 | ; (display (pi 4000)) ; 55 | ; (newline) 56 | -------------------------------------------------------------------------------- /4.1/e-4.15.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 4.15. 2 | ; 3 | ; Given a one-argument procedure p and an object a, p is said 4 | ; to ``halt'' on a if evaluating the expression (p a) returns a value (as 5 | ; opposed to terminating with an error message or running forever). Show that 6 | ; it is impossible to write a procedure halts? that correctly determines 7 | ; whether p halts on a for any procedure p and object a. Use the following 8 | ; reasoning: If you had such a procedure halts?, you could implement the 9 | ; following program: 10 | 11 | ;(define (run-forever) (run-forever)) 12 | 13 | ;(define (try p) 14 | ;(if (halts? p p) 15 | ;(run-forever) 16 | ;'halted)) 17 | 18 | ; Now consider evaluating the expression (try try) and show that any possible 19 | ; outcome (either halting or running forever) violates the intended behavior of 20 | ; halts?. 21 | ; ------------------------------------------------------------ 22 | 23 | ; This exercise is pointing to one very fundamental topic in the theory of computation. 24 | ; So called [Halting problem](https://en.wikipedia.org/wiki/Halting_problem). 25 | ; Shortly, the problem is defined as a problem: given a program and an input, can we decide 26 | ; if program will halt (end execution and eventually return result) or it will run forever. 27 | ; 28 | ; Alan Turing proved that this kind of procedure can not be implemented. He defined the 29 | ; famous Turing machine as most general computational model in order to mathematically define 30 | ; properties of a computation and computer program and to prove the undecidability of this problem. 31 | 32 | ; Lets evaluate (try try) to see what we get. 33 | ; 34 | ; So, point is that if try doesn't halt, then during evaluation of try (halts? try try) it will start running forewer. 35 | ; In case when (halts? try try) returns true, then it will start running forever after it returns from evaluating if try halts. 36 | -------------------------------------------------------------------------------- /2.3/e-2.56.scm: -------------------------------------------------------------------------------- 1 | ; Exercise 2.56. 2 | ; 3 | ; Show how to extend the basic differentiator to handle more kinds of 4 | ; expressions. For instance, implement the differentiation rule 5 | ; 6 | ; d(u^n)/dx = n*u^(n-1)*du/dx 7 | 8 | ; by adding a new clause to the deriv program and defining appropriate 9 | ; procedures exponentiation?, base, exponent, and make-exponentiation. (You may 10 | ; use the symbol ** to denote exponentiation.) Build in the rules that anything 11 | ; raised to the power 0 is 1 and anything raised to the power 1 is the thing 12 | ; itself. 13 | ; ------------------------------------------------------------ 14 | 15 | (load "../common.scm") 16 | (load "../helpers.scm") 17 | (load "2.3.scm") 18 | 19 | ; augmented deriv function 20 | 21 | (define (deriv exp var) 22 | (cond ((number? exp) 0) 23 | ((variable? exp) 24 | (if (same-variable? exp var) 1 0)) 25 | ((sum? exp) 26 | (make-sum (deriv (addend exp) var) 27 | (deriv (augend exp) var))) 28 | ((product? exp) 29 | (make-sum 30 | (make-product (multiplier exp) 31 | (deriv (multiplicand exp) var)) 32 | (make-product (multiplicand exp) 33 | (deriv (multiplier exp) var)))) 34 | ((exponent? exp) 35 | (make-product 36 | (make-product (power exp) 37 | (make-exponent (base exp) (- (power exp) 1))) 38 | (deriv (base exp) var))) 39 | (else 40 | (error "unknown expression type" exp)))) 41 | 42 | (define (exponent? exp) 43 | (eq? (car exp) '**)) 44 | 45 | (define (make-exponent b p) 46 | (cond ((=number? p 0) 1) 47 | ((=number? p 1) b) 48 | (else (list '** b p)))) 49 | 50 | (define (base exp) (cadr exp)) 51 | (define (power exp) (caddr exp)) 52 | 53 | 54 | (output (deriv '(** (* x 3) 5) 'x)) 55 | --------------------------------------------------------------------------------