Compare commits

...

7 commits

Author SHA1 Message Date
2ca5e73a27 Add solutions to exercises from subsection 2.2.3
Notes:
The exercise 2.37 on Hexlet's site has an error, noted in the comments.
Also, their page for exercise 2.38 should probably have 0 tests.

And finally, I did not calculate the exact number in the final exercise
2.43, but I included a relevant discussion.
2025-02-12 16:16:13 +01:00
8f4c2125bc Add solutions to exercises from subsetion 2.2.2 2025-02-06 11:14:16 +01:00
da96368e0b Add solutions to exercises from subsection 2.2.1
In exercise 2.17, there is an error with the test on hexlets site, which
should be reported to them.
2025-02-06 11:08:54 +01:00
1b2b2dfec1 Add solutions to exercises from section 2.1
To be noted: the last two exercises, 2.15 and 2.16 were left unfinished,
and will be left for another time.
2025-02-05 15:17:47 +01:00
bc04031dff Add solutions to exercises from section 1.3 2025-02-05 14:36:47 +01:00
a697f52405 Add solutions to exercises from section 1.2
To be noted: the drawing in exercise 1.14 is unfinished. I did it in a
notebook, but haven't yet had the time to put it in a txt file.
2025-02-05 13:59:25 +01:00
16d2911936 Fix section 1.1 solutions so they run in Racket 2025-02-05 12:10:11 +01:00
85 changed files with 1864 additions and 6 deletions

View file

@ -1,4 +1,5 @@
#| BEGIN (Write your solution here) |# #lang sicp
(define (sqr x) (* x x)) (define (sqr x) (* x x))
(define (solution a b c) (define (solution a b c)
(cond ((and (<= a b) (<= a c)) (cond ((and (<= a b) (<= a c))
@ -6,4 +7,3 @@
((and (<= b a) (<= b c)) ((and (<= b a) (<= b c))
(+ (sqr a) (sqr c))) (+ (sqr a) (sqr c)))
(else (+ (sqr a) (sqr b))))) (else (+ (sqr a) (sqr b)))))
#| END |#

View file

@ -1,4 +1,4 @@
#| BEGIN (Write your solution here) |# #lang sicp
(define (average a b) (define (average a b)
(/ (+ a b) 2)) (/ (+ a b) 2))
@ -15,4 +15,3 @@
(define (square-root x) (define (square-root x)
(sqrt-iter 1.0 x)) (sqrt-iter 1.0 x))
#| END |#

View file

@ -1,4 +1,5 @@
#| BEGIN (Write your solution here) |# #lang sicp
(define (improve guess x) (define (improve guess x)
(/ (+ (/ x guess guess) (/ (+ (/ x guess guess)
(* 2 guess)) (* 2 guess))
@ -15,4 +16,3 @@
(define (cube-root x) (define (cube-root x)
(cbrt-iter 1.0 x)) (cbrt-iter 1.0 x))
#| END |#

25
ex-1.09.txt Normal file
View file

@ -0,0 +1,25 @@
For the first +:
(+ 4 5)
(inc (+ (dec 4) 5))
(inc (+ 3 5))
(inc (inc (+ (dec 3) 5)))
..
(inc (inc (inc (+ 1 5))))
..
(inc (inc (inc (inc (+ 0 5)))))
(inc (inc (inc (inc 5))))
(inc (inc (inc 6)))
(inc (inc 7))
(inc 8)
9
For the second +:
(+ 4 5)
(+ (dec 4) (inc 5))
(+ 3 6)
(+ 2 7)
(+ 1 8)
(+ 0 9)
9
First is recursive, second is iterative.

8
ex-1.10.scm Normal file
View file

@ -0,0 +1,8 @@
#lang sicp
(define (A x y)
(cond ((= y 0) 0)
((= x 0) (* 2 y))
((= y 1) 2)
(else (A (- x 1)
(A x (- y 1))))))

17
ex-1.10.txt Normal file
View file

@ -0,0 +1,17 @@
(A 1 10)
2**10
(A 2 4)
(A 1 (A 2 3))
(A 1 (A 1 (A 2 ))
2**2**2**2
(A 3 3)
(A 2 (A 3 2))
2P3
2t(4)
(f n) == 2*n
(g n) == 2**n
(h n) == 2**2**...**2 <- n times

24
ex-1.11.scm Normal file
View file

@ -0,0 +1,24 @@
#lang sicp
; recursive process
(define (f1 n)
(if (< n 3)
n
(+ (f1 (- n 1))
(* 2 (f1 (- n 2)))
(* 3 (f1 (- n 3))))))
; iterative process
; loop for n >= 3
(define (f-iter iter-count acc1 acc2 acc3)
(let ((new-val (+ acc1 (* 2 acc2) (* 3 acc3))))
(if (= iter-count 0)
new-val
(f-iter (- iter-count 1) new-val acc1 acc2))))
(define (f2 n)
(if (< n 3)
n
(f-iter (- n 3) (f2 2) (f2 1) (f2 0))))
; these are just 2,1,0 respectively, but I felt this looks cleaner

5
ex-1.12.scm Normal file
View file

@ -0,0 +1,5 @@
#lang sicp
(define (solution n k)
(cond ((or (= n 1) (= k 1) (= k n)) 1)
(else (+ (solution (- n 1) (- k 1)) (solution (- n 1) k)))))

11
ex-1.13.txt Normal file
View file

@ -0,0 +1,11 @@
Dokazemo indukcijom, prvo za Fib(0) i Fib(1), kao baze.
Zatim dokazemo da Fib(n), sto je Fib(n-1) + Fib(n-2) sto je (phi^(n-1) -
psi^(n-1) + phi^(n-2) - psi^(n-2))/sqrt(5) da je to jednako (phi^n -
psi^n)/sqrt(5), sto je ustv lako jer je: phi^n = phi^(n-1) + phi^(n-2), isto
vazi i za psi, pa se to malo razbije i pretumba, i dobijemo: Fib(n) = (phi^n -
psi^n)/sqrt(5), za svako n u N.
Razlog zasto ovo dokazuje da je Fib(n) uvek najblizi ceo broj jeste to da psi
~=~ 0.36 < 0.5, a psi^n <<< psi, kad n>1. Dakle razlika između Fib(n) i
phi^n/sqrt(5) je uvek manja od 0.5. Dakle najblizi je ceo broj.

10
ex-1.14.txt Normal file
View file

@ -0,0 +1,10 @@
It's a very big tree.....
57 nodes, i'm not gonna type it out, around half of it is cases like:
(cc 11 1)
/ \
(cc 11 0) (cc 10 1)
/ \
(cc 10 0) (cc 9 1)
/ \
(cc 9 0) (cc 8 1)
..................................

5
ex-1.15.txt Normal file
View file

@ -0,0 +1,5 @@
Every time we call sine we end up calling
(p (sine angle/3)), which becomes
(p (p (sine angle/3/3))), etc.
So we end up calling it once each time until angle reaches 0.1/
In other words ceil(log3(12.15/0.1)) = 5

8
ex-1.16.scm Normal file
View file

@ -0,0 +1,8 @@
#lang sicp
(define (expt-aux b n a)
(cond ((= n 0) a)
((even? n) (expt-aux (* b b) (/ n 2) a))
(else (expt-aux b (- n 1) (* a b)))))
(define (solution b n)
(expt-aux b n 1))

10
ex-1.17.scm Normal file
View file

@ -0,0 +1,10 @@
#lang sicp
(define (double x) (* 2 x))
(define (halve x) (/ x 2))
(define (*aux a b acc)
(cond ((= b 0) acc)
((even? b) (*aux (double a) (halve b) acc))
(else (*aux a (- b 1) (+ acc a)))))
(define (fast-mul a b)
(*aux a b 0))

1
ex-1.18.scm Normal file
View file

@ -0,0 +1 @@
; Actually, this was already solved in the previous exercise

17
ex-1.19.scm Normal file
View file

@ -0,0 +1,17 @@
#lang sicp
(define (fib n)
(fib-iter 1 0 0 1 n))
(define (fib-iter a b p q count)
(cond ((= count 0) b)
((even? count)
(fib-iter a
b
(+ (* p p) (* q q))
(+ (* 2 p q) (* q q))
(/ count 2)))
(else (fib-iter (+ (* b q) (* a q) (* a p))
(+ (* b p) (* a q))
p
q
(- count 1)))))

52
ex-1.20.txt Normal file
View file

@ -0,0 +1,52 @@
(gcd 206 40)
; 40 != 0
(gcd 40 (remainder 206 40))
; in the if, remainder is computed and it isn't zero - 1c
; but I'm pretty sure this doesn't mean the remainder as the
; argument to gcd is evaluated, so we get:
(gcd (remainder 206 40) (remainder 40 (remainder 206 40)))
; in the next if, the two nested remainders must be computed - 2c
; and we're left with
(gcd (remainder 40 (remainder 206 40))
(remainder (remainder 206 40)
(remainder 40 (remainder 206 40))))
; in the next, the nested 4 are computed - 4c
; and we have:
(gcd (remainder (remainder 206 40)
(remainder 40 (remainder 206 40)))
(remainder (remainder 40 (remainder 206 40))
(remainder (remainder 206 40)
(remainder 40 (remainder 206 40)))))
; and the nested 7 must be computed. This will actually return 0, and then the
; first arg (4 nested remainder calls) must be evaluated, and that's it, but
; let's generalize.
; counting n from 0:
; notice in each n-th recursive pass, we evaluate remainder G(n+1) times.
; But also our arguments (a, b) end up having G(n+1)-level and G(n+2)-level
; indented applications of remainder, respectively, previously they had G(n)
; and G(n+1)
; here G(0)=G(1)=0, and for n>1 G(n) = G(n-1) + G(n-2) + 1
; so: G | n
----+---
; 0 | 0
; 0 | 1
; 1 | 2
; 2 | 3
; 4 | 4
; 7 | 5
; this happens until n=4, which is the last function call because that's when
; the right hand (G(5) calls) will evaluate to zero. And the final result, the
left hand, (G(4) calls) will be evaluated, and return 2.
So ultimately, the number of calls that must happen is:
G(1) + G(2) + ... + G(5) + G(4) (again)
or, more generally, if it takes n steps to compute the GCD:
Sum(G(1)..G(n+1)) + G(n) calls to remainder will be required.
In out situation, this will be 0+1+2+4+7+4 = 18 calls.
In the applicative order, the situation is far simpler, every recursive pass,
except the last, requires 1 call to remainder, so 4 calls.

18
ex-1.21.scm Normal file
View file

@ -0,0 +1,18 @@
#lang sicp
(define (square x) (* x x))
(define (smallest-divisor n)
(find-divisor n 2))
(define (find-divisor n test-divisor)
(cond ((> (square test-divisor) n) n)
((divides? test-divisor n) test-divisor)
(else (find-divisor n (+ test-divisor 1)))))
(define (divides? a b)
(= (remainder b a) 0))
;> (smallest-divisor 199)
;199
;> (smallest-divisor 1999)
;1999
;> (smallest-divisor 19999)
;7

171
ex-1.22.scm Normal file
View file

@ -0,0 +1,171 @@
#lang sicp
(define (square x) (* x x))
(define (smallest-divisor n)
(find-divisor n 2))
(define (find-divisor n test-divisor)
(cond ((> (square test-divisor) n) n)
((divides? test-divisor n) test-divisor)
(else (find-divisor n (+ test-divisor 1)))))
(define (divides? a b)
(= (remainder b a) 0))
(define (prime? n)
(= n (smallest-divisor n)))
(define (timed-prime-test n)
(newline)
(display n)
(start-prime-test n (runtime)))
(define (start-prime-test n start-time)
(if (prime? n)
(report-prime (- (runtime) start-time))))
(define (report-prime elapsed-time)
(display " *** ")
(display elapsed-time))
#| BEGIN (Write your solution here) |#
(define (search-for-primes a b)
(cond ((> a b) '())
((not (even? a))
(timed-prime-test a)
(search-for-primes (+ a 2) b))
(else (search-for-primes (+ a 1) b))))
#| END |#
;;;; TESTED OUTPUT
;> (search-for-primes 1000 2000)
;
;1001
;1003
;1005
;1007
;1009 *** 1
;1011
;1013 *** 1
;1015
;1017
;1019 *** 1
;1021 *** 1
;1023
;1025
;1027
;1029
;1031 *** 2
;1033 *** 1
;1035
;1037
;1039 *** 2
;1041
;1043
;1045
;> (search-for-primes 10000 10100)
;
;10001
;10003
;10005
;10007 *** 7
;10009 *** 5
;10011
;10013
;10015
;10017
;10019
;10021
;10023
;10025
;10027
;10029
;10031
;10033
;10035
;10037 *** 4
;10039 *** 5
;10041
;10043
;10045
;10047
;10049
;10051
;10053
;10055
;10057
;10059
;10061 *** 5
;10063
;10065
;10067 *** 5
;10069 *** 4
;10071
;10073
;10075
;10077
;10079 *** 4
;10081
;10083
;10085
;10087
;10089
;10091 *** 5
;10093 *** 9
;10095
;10097
;10099 *** 7()
;> (search-for-primes 100000 100100)
;
;100001
;100003 *** 16
;100005
;100007
;100009
;100011
;100013
;100015
;100017
;100019 *** 15
;100021
;100023
;100025
;100027
;100029
;100031
;100033
;100035
;100037
;100039
;100041
;100043 *** 15
;100045
;100047
;100049 *** 17
;100051
;100053
;100055
;100057 *** 16
;100059
;100061
;100063
;100065
;100067
;100069 *** 16
;100071
;100073
;100075
;100077
;100079
;100081
;100083
;100085
;100087
;100089
;100091
;100093
;100095
;100097
;100099()

26
ex-1.23.scm Normal file
View file

@ -0,0 +1,26 @@
#lang sicp
(define (square x) (* x x))
;(define (next x)
; (if (= x 2)
; 3
; (+ x 2)))
(define (next x) (+ x 1))
(define (smallest-divisor n)
(find-divisor n 2))
(define (find-divisor n test-divisor)
(cond ((> (square test-divisor) n) n)
((divides? test-divisor n) test-divisor)
(else (find-divisor n (next test-divisor)))))
(define (divides? a b)
(= (remainder b a) 0))
(define (time-sd n)
(define start-time (runtime))
(smallest-divisor n)
(- (runtime) start-time))
; comparing (time-sd 100069) with the new and old versions
; it's roughly a 1.5 factor increase, likely because the if
; statement checking is slightly more expensive than simply increasing
; by one

54
ex-1.24.scm Normal file
View file

@ -0,0 +1,54 @@
#lang sicp
(define (square x) (* x x))
(define (expmod base exp m)
(cond ((= exp 0) 1)
((even? exp)
(remainder (square (expmod base (/ exp 2) m))
m))
(else
(remainder (* base (expmod base (- exp 1) m))
m))))
(define (smallest-divisor n)
(find-divisor n 2))
(define (find-divisor n test-divisor)
(cond ((> (square test-divisor) n) n)
((divides? test-divisor n) test-divisor)
(else (find-divisor n (+ test-divisor 1)))))
(define (divides? a b)
(= (remainder b a) 0))
(define (fermat-test n)
(define (try-it a)
(= (expmod a n n) a))
(try-it (+ 1 (random (- n 1)))))
(define (fast-prime? n times)
(cond ((= times 0) true)
((fermat-test n) (fast-prime? n (- times 1)))
(else false)))
(define (prime? n)
(= n (smallest-divisor n)))
(define (timed-prime-test n)
(newline)
(display n)
(start-prime-test n (runtime)))
(define (start-prime-test n start-time)
(if (fast-prime? n 10)
(report-prime (- (runtime) start-time))))
(define (report-prime elapsed-time)
(display " *** ")
(display elapsed-time))
(define (search-for-primes a b)
(cond ((> a b) '())
((not (even? a))
(timed-prime-test a)
(search-for-primes (+ a 2) b))
(else (search-for-primes (+ a 1) b))))

2
ex-1.25.txt Normal file
View file

@ -0,0 +1,2 @@
No, because it would produce extremely large exponentials, which
would be computed more slowly. And computing the remainder would be extremely slow.

10
ex-1.26.txt Normal file
View file

@ -0,0 +1,10 @@
Essentially, instead of us halving the time of computation,
every time we have an even number, we instead halve the expmod call
but then, make that call twice, in other words, instead of
(specifically for even number):
T(n) = O(1) + T(n/2)
we get:
T(n) = O(1) + 2*T(n/2), which is going to give us roughly:
O(n)
We get a recursion tree, growing exponentially with at every recursive call,
of which there are O(log n), so exp(log(n)) = n.

27
ex-1.27.scm Normal file
View file

@ -0,0 +1,27 @@
#lang sicp
(define (square x) (* x x))
(define (expmod-aux base exp n acc)
(cond ((= 0 exp) acc)
((even? exp) (expmod-aux (remainder (square base) n) (/ exp 2) n acc))
(else (expmod-aux base (- exp 1) n (remainder (* acc base) n)))))
(define (expmod base exp n)
(expmod-aux base exp n 1))
(define (carmichael-test-aux n a)
(cond ((>= a n) #t)
((= (expmod a n n) a) (carmichael-test-aux n (+ a 1)))
(else #f)))
(define (carmichael-test n)
(carmichael-test-aux n 0))
;> (carmichael-test 561)
;#t
;> (carmichael-test 1105)
;#t
;> (carmichael-test 1729)
;#t
;> (carmichael-test 2465)
;#t
;> (carmichael-test 2821)
;#t
;> (carmichael-test 6601)
;#t
;>

24
ex-1.28.scm Normal file
View file

@ -0,0 +1,24 @@
#lang sicp
(define (square n) (* n n))
(define (expmod-aux base exp n acc)
(define sqr (remainder (square base) n))
(cond ((= 0 exp) acc)
((even? exp)
(if (and (= sqr 1)
(not (= base 1))
(not (= base (- n 1))))
0
(expmod-aux sqr (/ exp 2) n acc)))
(else (expmod-aux base (- exp 1) n (remainder (* acc base) n)))))
(define (expmod base exp n)
(expmod-aux base exp n 1))
(define (miller-rabin-test n)
(define (try-it a)
(= (expmod a (- n 1) n) 1))
(if (and (even? n) (not (= 2 n)))
#f
(try-it (+ 1 (random (- n 1))))))

22
ex-1.29.scm Normal file
View file

@ -0,0 +1,22 @@
#lang sicp
; (define (cube x) (* x x x))
(define (sum term a next b)
(if (> a b)
0
(+ (term a)
(sum term (next a) next b))))
(define (inc x) (+ 1 x))
(define (simpson f a b n)
(define h (/ (- b a) n))
(define (add-h x) (+ x h))
(define (term i)
(cond ((= i 0) (f a))
((= i n) (f b))
((even? i) (* 2 (f (+ a (* i h)))))
(else (* 4 (f (+ a (* i h)))))))
(* h
(/ 1.0 3)
(sum term 0 inc n)))

8
ex-1.30.scm Normal file
View file

@ -0,0 +1,8 @@
#lang sicp
(define (sum term a next b)
(define (iter a result)
(if (> a b)
result
(iter (next a) (+ result (term a)))))
(iter a 0))

25
ex-1.31.scm Normal file
View file

@ -0,0 +1,25 @@
#lang sicp
(define (product term a next b)
(define (iter a result)
(if (> a b)
result
(iter (next a) (* result (term a)))))
(iter a 1))
(define (pi-prod n)
(define (pi-term i)
(if (even? i)
(/ (+ i 2) (+ i 1))
(/ (+ i 1) (+ i 2))))
(product pi-term 1 inc n))
;(define (inc x) (+ x 1))
(define (factorial n)
(product identity 1 inc n))
(define (product-rec term a next b)
(if (> a b)
1
(* (term a) (product-rec term (next a) next b))))

13
ex-1.32.scm Normal file
View file

@ -0,0 +1,13 @@
#lang sicp
(define (accumulate combiner null-value term a next b)
(define (iter a result)
(if (> a b)
result
(iter (next a) (combiner result (term a)))))
(iter a null-value))
(define (sum term a next b)
(accumulate + 0 term a next b))
(define (product term a next b)
(accumulate * 1 term a next b))

39
ex-1.33.scm Normal file
View file

@ -0,0 +1,39 @@
#lang sicp
(define (filtered-accumulate combiner
null-value
term
a
next
b
pred?)
(define (iter a result)
(cond ((> a b) result)
((pred? a) (iter (next a)
(combiner result (term a))))
(else (iter (next a) result))))
(iter a null-value))
(define (square x) (* x x))
(define (smallest-divisor n) (find-divisor n 2))
(define (find-divisor n test-divisor)
(cond ((> (square test-divisor) n) n)
((divides? test-divisor n) test-divisor)
(else (find-divisor n (+ test-divisor 1)))))
(define (divides? a b) (= (remainder b a) 0))
(define (prime? n)
(= n (smallest-divisor n)))
(define (prime-square-sum a b)
(filtered-accumulate + 0 square a inc b prime?))
(define (gcd a b)
(if (= b 0)
a
(gcd b (remainder a b))))
(define (rel-prime-product n)
(define (rel-prime-n? i)
(= (gcd i n) 1))
(filtered-accumulate * 1 identity 1 inc n rel-prime-n?))

4
ex-1.34.txt Normal file
View file

@ -0,0 +1,4 @@
(f f)
(f 2)
(2 2)
Error: 2 is not a procedure

24
ex-1.35.scm Normal file
View file

@ -0,0 +1,24 @@
#lang sicp
(define tolerance 0.00001)
(define (fixed-point f first-guess)
(define (close-enough? v1 v2)
(< (abs (- v1 v2)) tolerance))
(define (try guess)
(let ((next (f guess)))
(if (close-enough? guess next)
next
(try next))))
(try first-guess))
; below is phi
;
; proof: f(x) = 1 + 1/x
; f(phi) = 1 + 1/((1+sqrt(5))/2) = 1 + 2/(1+sqrt(5)) =
; (1+sqrt(5))/(1+sqrt(5)) + 2/(1+sqrt(5)) =
; ( 3+sqrt(5) ) / (1+sqrt(5)) (multiply and divide by (1-sqrt(5)))
; you get: (1+sqrt(5))/2 qed
;
(define phi (fixed-point (lambda (x) (+ 1 (/ 1 x))) 2.0))
(define solution (lambda (x) (+ 1 (/ 1 x))))

28
ex-1.36.scm Normal file
View file

@ -0,0 +1,28 @@
#lang sicp
(define tolerance 0.00001)
(define (fixed-point f guess)
(define new-guess (f guess))
(cond ((< (abs (- guess new-guess)) tolerance)
(display new-guess)
(newline)
(f guess))
(else
(display new-guess)
(newline)
(fixed-point f new-guess))))
; 34 steps without damping
(define solution (fixed-point
(lambda (x) (/ (log 1000)
(log x)))
2.0))
(newline)
(newline)
(newline)
; 9 steps with average damping
(define solution-damped
(fixed-point (lambda (x) (/ (+ x
(/ (log 1000)
(log x)))
2.0))
2.0))

11
ex-1.37.scm Normal file
View file

@ -0,0 +1,11 @@
#lang sicp
(define (cont-frac n d k)
(define (cf-acc n d k i)
(if (= k i)
(/ (n i) (d i))
(/ (n i) (+ (d i) (cf-acc n d k (+ i 1))))))
(cf-acc n d k 0))
; it takes exactly k = 10, for 1/phi to be estimated accurately up to the
; 4th decimal

16
ex-1.38.scm Normal file
View file

@ -0,0 +1,16 @@
#lang sicp
(define (cont-frac n d k)
(define (cf-acc n d k i)
(if (= k i)
(/ (n i) (d i))
(/ (n i) (+ (d i) (cf-acc n d k (+ i 1))))))
(cf-acc n d k 0))
(define (e k)
(+ 2.0 (cont-frac (lambda (i) 1.0)
(lambda (i)
(if (= (remainder i 3) 1)
(* 2.0 (/ (+ i 2) 3))
1.0))
k)))

15
ex-1.39.scm Normal file
View file

@ -0,0 +1,15 @@
#lang sicp
(define (cont-frac n d k)
(define (cf-acc n d k i)
(if (= k i)
(/ (n i) (d i))
(/ (n i) (+ (d i) (cf-acc n d k (+ i 1))))))
(cf-acc n d k 0))
(define (tan-cf x k)
(cont-frac (lambda (i) (if (= i 0)
x
(- (* x x))))
(lambda (i) (+ 1.0 (* 2.0 i)))
k))

7
ex-1.40.scm Normal file
View file

@ -0,0 +1,7 @@
#lang sicp
(define (cubic a b c)
(lambda (x) (+ (* x x x)
(* a x x)
(* b x)
c)))

12
ex-1.41.scm Normal file
View file

@ -0,0 +1,12 @@
#lang sicp
(define (double f)
(lambda (x) (f (f x))))
; double doubles the function application, so when you do
; (double double) you actually get back a function which performs
; a (double (double f)) on a given f, in other words, it
; applies f 4 times. When we do this three times,
; (double (double double)) gives us a function, that for f gives
; (double (double (double (double f)))), which actually
; applies f sixteen times,
; so the result is 5+16 = 21.

4
ex-1.42.scm Normal file
View file

@ -0,0 +1,4 @@
#lang sicp
(define (compose f g)
(lambda (x) (f (g x))))

11
ex-1.43.scm Normal file
View file

@ -0,0 +1,11 @@
#lang sicp
(define (identity x) x)
(define (compose f g)
(lambda (x) (f (g x))))
(define (repeated f n)
(if (= n 0)
identity
(compose f (repeated f (- n 1)))))

9
ex-1.44.scm Normal file
View file

@ -0,0 +1,9 @@
#lang sicp
(define (smooth f)
(define dx 0.0001)
(lambda (x)
(/ (+ (f (- x dx))
(f x)
(f (+ x dx)))
3)))

81
ex-1.45.scm Normal file
View file

@ -0,0 +1,81 @@
#lang sicp
; here, I will prove an upper bound on the number of average
; dampings needed for a given n while calculating nth-root
; in other words, you might need fewer damps than what i prove
; but you definitely have enough damps with this method.
; with n, we need the transform y -> x/y^(n-1)
; one thing which will guarrantee convergence is that the
; derivative of the transform is 0 < d < 1 AFTER the point of
; convergence we're looking for, for example
; derivative of this transform is for SQUARE ROOT is:
; transf: y -> x/y
; deriv: -(x/y^2), which for y>=sqrt(x) will give us a number:
; -1 <= N <= 0, so we can't guarrantee divergence.
; when we average damp, the deriv becomes:
; ( -(x/y^2) + 1 ) / 2, now it lands between 0 and 1.
; for cube root, transform is y->x/y^2, deriv is:
; -2(x/y^3), this lands in the range -2 < d < 0
; if we damp it once, we get the range -0.5 < d < 0.5, so we
; need to damp again to get the range 0.25 < d < 0.75
; in general for calculating the nth-root, we need the
; transform y -> x/y^(n-1), which will have the derivative:
; -(n-1)(x/y^n), the derivative will for y>(nth-root x)
; fall in the range -(n-1) < d < 0.
; Note that when we average damp the function, this range
; becomes -((n-1+1)/2) = -n/2 < d < 0.5, then
; ((-n/2)+1) / 2 < d < 0.75
; when we play around we see that for n-1 = 1, we only need
; one damp, for n-1 = 2 or 3 we need two damps
; for n-1 = 4 or 5 or 6 or 7, we need three, in general
; for n >= 2, we need ceil(log2(n)), average damps
; again, note, we might actually need fewer damps, this is
; just and upper-bound, however, luckily, we can never
; over-damp with this function when coming from the right
; because the upper bound for the derivative values will
; always be 0.5,0.75,0.875,.... < 1.
; so with enought damping we can always get a range of derivs
; in 0 < d < 1.
(define (log2 x)
(/ (log x) (log 2)))
(define tolerance 0.00001)
(define (fixed-point f first-guess)
(define (close-enough? v1 v2)
(< (abs (- v1 v2)) tolerance))
(define (try guess)
(let ((next (f guess)))
(if (close-enough? guess next)
next
(try next))))
(try first-guess))
(define (identity x) x)
(define (compose f g)
(lambda (x) (f (g x))))
(define (repeated f n)
(if (= n 0)
identity
(compose f (repeated f (- n 1)))))
(define (average a b)
(/ (+ a b) 2))
(define (average-damp f)
(lambda (x) (average x (f x))))
; returns a procedure
(define (nth-root n)
(let* ((damp-number (ceiling (log2 n)))
(damps (repeated average-damp damp-number)))
(lambda (x)
(fixed-point (damps (lambda (y)
(/ x (expt y (- n 1)))))
(exact->inexact x)))))

24
ex-1.46.scm Normal file
View file

@ -0,0 +1,24 @@
#lang sicp
(define (iterative-improve good-enough?
improve)
(define (rec-procedure guess)
(define new-guess (improve guess))
(if (good-enough? guess new-guess)
new-guess
(rec-procedure new-guess)))
rec-procedure)
(define (square x)
(* x x))
(define (average a b)
(/ (+ a b)
2))
(define (sqrt x)
(define tolerance 0.000001)
(define (good-enough? guess)
(< (abs (- (square guess) x)) tolerance))
(define (improve guess)
(average guess (/ x guess)))
(iterative-improve good-enough? improve))

8
ex-2.01.scm Normal file
View file

@ -0,0 +1,8 @@
#lang sicp
(define (make-rat n d)
(let ((g (gcd n d)))
(cond ((= d 0)
(error "Cannot make-rat with denominator 0"))
((< d 0) (cons (- (/ n g)) (- (/ d g))))
(else (cons (/ n g) (/ d g))))))

24
ex-2.02.scm Normal file
View file

@ -0,0 +1,24 @@
#lang sicp
(define (make-segment a b)
(cons a b))
(define (start-segment s)
(car s))
(define (end-segment s)
(cdr s))
(define (make-point x y)
(cons x y))
(define (x-point p)
(car p))
(define (y-point p)
(cdr p))
(define (average a b)
(/ (+ a b) 2.0))
(define (midpoint-segment s)
(make-point (average (x-point (start-segment s))
(x-point (end-segment s)))
(average (y-point (start-segment s))
(y-point (end-segment s)))))

34
ex-2.03.scm Normal file
View file

@ -0,0 +1,34 @@
#lang sicp
(define (make-point x y)
(cons x y))
(define (x-point p)
(car p))
(define (y-point p)
(cdr p))
; top-left point, bottom-right point representation
(define (tlbr-rect a b)
(cons 'tlbr (cons a b)))
; center point, width, height representation
(define (cpwh-rect p w h)
(cons 'cpwh
(cons p
(cons w h))))
(define (height rect)
(cond ((eq? 'cpwh (car rect)) (cdddr rect))
(else (abs (- (y-point (cadr rect))
(y-point (cddr rect)))))))
(define (width rect)
(cond ((eq? 'cpwh (car rect)) (caddr rect))
(else (abs (- (x-point (cadr rect))
(x-point (cddr rect)))))))
(define (perimeter rect)
(* 2 (+ (width rect) (height rect))))
(define (area rect)
(* (width rect) (height rect)))

4
ex-2.04.scm Normal file
View file

@ -0,0 +1,4 @@
#lang sicp
(define (cdr z)
(z (lambda (p q) q)))

29
ex-2.05.scm Normal file
View file

@ -0,0 +1,29 @@
#lang sicp
(define (cons a b)
(* (expt 2 a)
(expt 3 b)))
(define (car pair)
(if (= (remainder pair 3) 0)
(car (/ pair 3))
(log2 pair)))
(define (cdr pair)
(if (= (remainder pair 2) 0)
(cdr (/ pair 2))
(log3 pair)))
(define (log2 num)
(define (aux num acc)
(if (<= num 1)
acc
(aux (/ num 2) (+ acc 1))))
(aux num 0))
(define (log3 num)
(define (aux num acc)
(if (<= num 1)
acc
(aux (/ num 3) (+ acc 1))))
(aux num 0))

14
ex-2.06.scm Normal file
View file

@ -0,0 +1,14 @@
#lang sicp
(define one (lambda (f)
(lambda (x)
(f x))))
(define two (lambda (f)
(lambda (x)
(f (f x)))))
(define (+ a b)
(lambda (f)
(lambda (x)
((a f) ((b f) x)))))

7
ex-2.07.scm Normal file
View file

@ -0,0 +1,7 @@
#lang sicp
(define (lower-bound i)
(car i))
(define (upper-bound i)
(cdr i))

15
ex-2.08.scm Normal file
View file

@ -0,0 +1,15 @@
#lang sicp
(define (make-interval a b) (cons a b))
(define (lower-bound i)
(car i))
(define (upper-bound i)
(cdr i))
(define (sub-interval a b)
(make-interval (- (lower-bound a)
(upper-bound b))
(- (upper-bound a)
(lower-bound b))))

31
ex-2.09.scm Normal file
View file

@ -0,0 +1,31 @@
#lang sicp
#|
(define (add-interval x y)
(make-interval (+ (lower-bound x) (lower-bound y))
(+ (upper-bound x) (upper-bound y))))
(define (sub-interval a b)
(make-interval (- (lower-bound a) (upper-bound b))
(- (upper-bound a) (lower-bound b))))
Notice that in add-interval, the lower-bound is low-x + low-y.
Meanwhile the higher-bound is high-x + high-y = low-x + width-x
+ low-y + width-y = low-sum + (width-x + width-y).
So width-sum = width-x + width-y.
Similar logic applies to sub-interval.
For mul-interval it's enough to see that
(mul-interval (make-interval 1 2) (make-interval 3 4)) =
(3 . 8) -> width = 5
doesn't have the same width as:
(mul-interval (make-interval 3 4) (make-interval 3 4)) =
(9 . 16) -> width = 7
despite the fact that in both cases, the intervals have widths:
1 and 1.
|#
; This code is only here to pass hexlet's test, which I'm not sure is
; necessary.
(define (width x) (/ (- (upper-bound x) (lower-bound x))
2))

25
ex-2.10.scm Normal file
View file

@ -0,0 +1,25 @@
#lang sicp
(define (make-interval a b) (cons a b))
(define (lower-bound i)
(car i))
(define (upper-bound i)
(cdr i))
(define (mul-interval x y)
(let ((p1 (* (lower-bound x) (lower-bound y)))
(p2 (* (lower-bound x) (upper-bound y)))
(p3 (* (upper-bound x) (lower-bound y)))
(p4 (* (upper-bound x) (upper-bound y))))
(make-interval (min p1 p2 p3 p4)
(max p1 p2 p3 p4))))
(define (div-interval x y)
(if (<= (* (lower-bound y) (upper-bound y)) 0)
(error "division by zero")
(mul-interval
x
(make-interval (/ 1.0 (upper-bound y))
(/ 1.0 (lower-bound y))))))

75
ex-2.11.scm Normal file
View file

@ -0,0 +1,75 @@
#lang sicp
(define (make-interval a b) (cons a b))
(define (lower-bound i)
(car i))
(define (upper-bound i)
(cdr i))
; explanation for sgn-interval:
; an interval has sign 0 if it has negative and non-negative
; values (ie. it spans over zero)
; a sign of -1 if all of it's values are negative
; and a sign of 1 if all of it's values are non-negative
(define (sgn-interval a)
(let ((low-a (lower-bound a))
(upp-a (upper-bound a)))
(cond ((< upp-a 0) -1)
((>= low-a 0) 1)
(else 0))))
(define (mul-interval x y)
(let* ((sgn-x (sgn-interval x))
(sgn-y (sgn-interval y))
(sgn-pair (cons sgn-x sgn-y)))
(cond ((equal? sgn-pair '(-1 . -1))
(make-interval (* (upper-bound x)
(upper-bound y))
(* (lower-bound x)
(lower-bound y))))
((equal? sgn-pair '(-1 . 0))
(make-interval (* (lower-bound x)
(upper-bound y))
(* (lower-bound x)
(lower-bound y))))
((equal? sgn-pair '(-1 . 1))
(make-interval (* (lower-bound x)
(upper-bound y))
(* (upper-bound x)
(lower-bound y))))
((equal? sgn-pair '(0 . -1))
(make-interval (* (upper-bound x)
(lower-bound y))
(* (lower-bound x)
(lower-bound y))))
; the difficult case
((equal? sgn-pair '(0 . 0))
(let ((uu (* (upper-bound x) (upper-bound y)))
(ul (* (upper-bound x) (lower-bound y)))
(lu (* (lower-bound x) (upper-bound y)))
(ll (* (lower-bound x) (lower-bound y))))
(make-interval (min ul lu)
(max uu ll))))
((equal? sgn-pair '(0 . 1))
(make-interval (* (lower-bound x)
(upper-bound y))
(* (upper-bound x)
(upper-bound y))))
((equal? sgn-pair '(1 . -1))
(make-interval (* (upper-bound x)
(lower-bound y))
(* (lower-bound x)
(upper-bound y))))
((equal? sgn-pair '(1 . 0))
(make-interval (* (upper-bound x)
(lower-bound y))
(* (upper-bound x)
(upper-bound y))))
((equal? sgn-pair '(1 . 1))
(make-interval (* (lower-bound x)
(lower-bound y))
(* (upper-bound x)
(upper-bound y)))))))

23
ex-2.12.scm Normal file
View file

@ -0,0 +1,23 @@
#lang sicp
(define (make-interval a b) (cons a b))
(define (lower-bound i)
(car i))
(define (upper-bound i)
(cdr i))
(define (make-center-percent c p)
(make-interval (- c (* c p 1/100))
(+ c (* c p 1/100))))
(define (center i)
(/ (+ (lower-bound i) (upper-bound i)) 2))
(define (width i)
(/ (- (upper-bound i) (lower-bound i)) 2))
(define (percent i)
(* (/ (width i) (center i)) 100))

10
ex-2.13.txt Normal file
View file

@ -0,0 +1,10 @@
Let's limit our argument for positive numbers:
a+-wa * b+-wb = [(a-wa)*(b-wb), (a+wa)*(b+wb)]
[a*b - a*wb - b*wb + wa*wb, a*b + a*wb + b*wa + wa*wb]
if we assume wa*wb is insignificantly small, we get:
a*b+-(a*wb+b*wa)
tolerances are the following:
ta = wa/a
tb = wb/b
tab = (a*wb+b*wa)/(a*b) = (a*b*tb + a*b*ta)/(a*b) = ta+tb

72
ex-2.14.scm Normal file
View file

@ -0,0 +1,72 @@
#lang sicp
(define make-interval cons)
(define (lower-bound i)
(car i))
(define (upper-bound i)
(cdr i))
(define (sub-interval a b)
(make-interval (- (lower-bound a)
(upper-bound b))
(- (upper-bound a)
(lower-bound b))))
(define (mul-interval x y)
(let ((p1 (* (lower-bound x) (lower-bound y)))
(p2 (* (lower-bound x) (upper-bound y)))
(p3 (* (upper-bound x) (lower-bound y)))
(p4 (* (upper-bound x) (upper-bound y))))
(make-interval (min p1 p2 p3 p4)
(max p1 p2 p3 p4))))
(define (add-interval x y)
(make-interval (+ (lower-bound x) (lower-bound y))
(+ (upper-bound x) (upper-bound y))))
(define (div-interval x y)
(if (<= (* (lower-bound y) (upper-bound y)) 0)
(error "division by zero")
(mul-interval
x
(make-interval (/ 1.0 (upper-bound y))
(/ 1.0 (lower-bound y))))))
(define (par1 r1 r2)
(div-interval (mul-interval r1 r2)
(add-interval r1 r2)))
(define (par2 r1 r2)
(let ((one (make-interval 1 1)))
(div-interval
one (add-interval (div-interval one r1)
(div-interval one r2)))))
(define example-1 (make-interval 1 2))
(define example-2 (make-interval 0.999 1.001))
(div-interval example-1 example-1)
;(0.5 . 2.0)
(div-interval example-2 example-2)
;(0.9980019980019982 . 1.002002002002002)
; It's simplest to explain this using the previous result
; that the tolerance of a product of a*b, is roughly the
; sum of the tolerances (if the tolerances are small
; relative to the center point)
; We can also derive that the tolerance of 1/a is equal to
; the tolerance of a.
; Proof:
; a = [x-w,x+w], t_a = w/x
; 1/a = [1/(x+w), 1/(x-w)] =
; [(1/(x+w)) * (x-w)/(x-w), (1/(x-w)) * (x+w)/(x+w)] =
; [(x-w)/(x^2-w^2), (x+w)/(x^2-w^2)] =
; x/(x^2-w^2) +- w/(x^2-w^2)
; the tolerance of the product is then:
; (w/(x^2-w^2)) / (x/(x^2-w^2)) = w/x, same as t_a.
;
; This means, using the previous approximation, that the
; expression a/a = 1, rather than having a tolerance of 0
; is going to have a tolerance doubling that of a.

15
ex-2.15-NOT-DONE.txt Normal file
View file

@ -0,0 +1,15 @@
This is mostly explained in the previous exercise.
When it comes to par1 and par2 specifically, we should examine
the formulas themselves:
((R1+-t1*R1)*(R2+-t2*R2)) / (R1+-t1*R1 + R2+-t2*R2) =
(R1*R2 +-t1*R1*R2 +-t2*R2*R1 +-t1*t2*R1*R2) /
(R1+R2+-t1*R1+-t2*R2) =
(R1*R2 +-t1*R1*R2 +-t2*R2*R1 +-t1*t2*R1*R2) /
(R1+R2+-t1*R1+-t2*R2) * (R1+R2-+t1*R1-+t2*R2)/(R1+R2-+t1*R1-+t2*R2) =
(R1*R2 +-t1*R1*R2 +-t2*R2*R1 +-t1*t2*R1*R2) /
(R1+R2+-t1*R1+-t2*R2) * (R1+R2-+t1*R1-+t2*R2)/(R1+R2-+t1*R1-+t2*R2) =
1 / (1/(R1+-t1)+1/(R2+-t2)) =
1 / ((R1-+t1)/(R1^2-t1^2) + (R2-+t2)/(R2^2-t2^2)) =

5
ex-2.16-NOT-DONE.txt Normal file
View file

@ -0,0 +1,5 @@
One issue is the afformention reuse of intervals, another is
floating point arithmetic. In order to solve the problem of making
all expressions maximally precise, we would need to make a package that can
take a given arithmetic expression and minimize it. This is
probaly very hard but not impossible.

7
ex-2.17.scm Normal file
View file

@ -0,0 +1,7 @@
#lang sicp
(define (last-pair list)
(cond ((null? list) (error "Can't get last element of empty list"))
((null? (cdr list)) list)
(else (last-pair (cdr list)))))

9
ex-2.18.scm Normal file
View file

@ -0,0 +1,9 @@
#lang sicp
(define (reverse lst)
(define (rev-aux lst acc)
(if (null? lst)
acc
(rev-aux (cdr lst) (cons (car lst)
acc))))
(rev-aux lst '()))

14
ex-2.19.scm Normal file
View file

@ -0,0 +1,14 @@
#lang sicp
(define (first-denomination coin-values)
(car coin-values))
(define (except-first-denomination coin-values)
(cdr coin-values))
(define (no-more? coin-values)
(null? coin-values))
; The answer will not be affected by the order of the list. We
; are still dividing cases into "doesn't use the first coin"
; and "uses at least one instance of first coin". However I
; suspect it will impact the performace, although I haven't
; formally proven it.

10
ex-2.20.scm Normal file
View file

@ -0,0 +1,10 @@
#lang sicp
(define (same-parity fst . lst)
(define (same-parity-aux parity lst)
(cond ((null? lst) '())
((equal? parity (even? (car lst)))
(cons (car lst) (same-parity-aux parity (cdr lst))))
(else (same-parity-aux parity (cdr lst)))))
(same-parity-aux (even? fst)
(cons fst lst)))

11
ex-2.21.scm Normal file
View file

@ -0,0 +1,11 @@
#lang sicp
(define (square x) (* x x))
(define (square-list items)
(if (null? items)
nil
(cons (square (car items)) (square-list (cdr items)))))
(define (square-list2 items)
(map square items))

18
ex-2.22.txt Normal file
View file

@ -0,0 +1,18 @@
When we are running the iter line:
(iter (cdr things)
(cons (square (car things))
answer))))
We are essentially pushing on the "answer" accumulator list
like a stack, so when we start with items = (1 2 3), answer =
().
When we run the loop once we get:
things = (2 3), answer = (1)
things = (3), answer = (4 1)
things = (), answer = (9 4 1).
When Louis changes the order in the cons, he just produces the
following:
things = (1 2 3), answer = ()
things = (2 3), answer = (() . 1)
things = (3), answer = ((() . 1) . 4)
things = (), answer = (((() . 1) . 4) . 9)

7
ex-2.23.scm Normal file
View file

@ -0,0 +1,7 @@
#lang sicp
(define (my-for-each func list)
(if (null? list)
#t
(begin (func (car list))
(my-for-each func (cdr list)))))

20
ex-2.24.txt Normal file
View file

@ -0,0 +1,20 @@
Result:
(1 (2 (3 4)))
Box-and-pointer diagram:
[.|.] -> [.|.] -> nil
V V
1 [.|.] -> [.|.] -> nil
V V
2 [.|.] -> [.|.] -> nil
V V
3 4
Tree structure:
(1 (2 (3 4)))
/ \
1 (2 (3 4))
/ \
2 (3 4)
/ \
3 4

3
ex-2.25.txt Normal file
View file

@ -0,0 +1,3 @@
cadaddr
caar
cadadadadadadr

3
ex-2.26.txt Normal file
View file

@ -0,0 +1,3 @@
(1 2 3 4 5 6)
((1 2 3) 4 5 6)
((1 2 3) (4 5 6))

15
ex-2.27.scm Normal file
View file

@ -0,0 +1,15 @@
#lang sicp
(define (dr-aux x acc)
(if (null? x)
acc
(let ((head (car x))
(tail (cdr x)))
(if (pair? head)
(dr-aux tail
(cons (deep-reverse head)
acc))
(dr-aux tail
(cons head acc))))))
(define (deep-reverse x)
(dr-aux x '()))

16
ex-2.28.scm Normal file
View file

@ -0,0 +1,16 @@
#lang sicp
(define (list? x)
(or (null? x) (pair? x)))
(define (fringe tree)
(if (null? tree)
'()
(let* ((head (car tree))
(tail (cdr tree))
(h-list (if (list? head) ; if it's a subtree
(fringe head) ; turn it into a list
; otherwise, just make a
; one-element list
(list head))))
(append h-list (fringe tail)))))

60
ex-2.29.scm Normal file
View file

@ -0,0 +1,60 @@
#lang sicp
(define (make-mobile left right)
(list left right))
; a. part 1
(define (left-branch mobile)
(car mobile))
(define (right-branch mobile)
(cadr mobile))
(define (make-branch length structure)
(list length structure))
; a. part 2
(define (branch-length branch)
(car branch))
(define (branch-structure branch)
(cadr branch))
; b
(define (total-weight mobile)
(if (number? mobile)
mobile
(+ (total-weight (branch-structure (left-branch mobile)))
(total-weight (branch-structure (right-branch mobile))))))
; c, with O(n) complexity, because the basic algorithm would
; recalculate weights of lower level submobiles, each node is
; calculated h times, where h is the number of it's ancestors
; for a typical mobile, this would cause the complexity to be
; O(log(n) * n)
(define (mobile-balanced? mobile)
; this returns a pair, a bool describing whether the mobile
; is balanced, and a number, describing the total weight of
; the mobile
(define (balanced-aux mobile)
(if (number? mobile)
(cons #t mobile)
(let* ((left-submobile (branch-structure (left-branch mobile)))
(right-submobile (branch-structure (right-branch mobile)))
(len-left (branch-length (left-branch mobile)))
(len-right (branch-length (right-branch mobile)))
(bal-aux-left (balanced-aux left-submobile))
(bal-aux-right (balanced-aux right-submobile))
(balanced-left? (car bal-aux-left))
(balanced-right? (car bal-aux-right))
(weight-left (cdr bal-aux-left))
(weight-right (cdr bal-aux-right)))
(cons (and balanced-left?
balanced-right?
(= (* weight-left len-left)
(* weight-right len-right)))
(+ weight-left weight-right)))))
(car (balanced-aux mobile)))
; d. The way we wrote the code so far, we've managed to
; cleanly separate the internals of the mobile and branch
; structures from the code which uses them, so the only thing
; that needs to be changed is the selectors. In this case in
; particular, we only need to change the right-branch, and
; branch-structure selectors, by changing the cadr into a cdr

13
ex-2.30.scm Normal file
View file

@ -0,0 +1,13 @@
#lang sicp
(define (square x) (* x x))
;(define (square-tree tree)
; (cond ((null? tree) '())
; ((number? tree) (square tree))
; (else (cons (square-tree (car tree))
; (square-tree (cdr tree))))))
(define (square-tree tree)
(if (number? tree)
(square tree)
(map square-tree tree)))

7
ex-2.31.scm Normal file
View file

@ -0,0 +1,7 @@
#lang sicp
(define (tree-map f tree)
(cond ((null? tree) '())
((pair? tree) (cons (tree-map f (car tree))
(tree-map f (cdr tree))))
(else (f tree))))

9
ex-2.32.scm Normal file
View file

@ -0,0 +1,9 @@
#lang sicp
(define (subsets s)
(if (null? s)
(list nil)
(let ((rest (subsets (cdr s))))
(append rest (map (lambda (set) (cons (car s)
set))
rest)))))

21
ex-2.33.scm Normal file
View file

@ -0,0 +1,21 @@
#lang sicp
(define (accumulate op initial sequence)
(if (null? sequence)
initial
(op (car sequence)
(accumulate op initial (cdr sequence)))))
(define (map p sequence)
(accumulate (lambda (x y) (cons (p x)
y))
nil
sequence))
(define (append seq1 seq2)
(accumulate cons seq2 seq1))
(define (inc x y) (+ y 1))
(define (length sequence)
(accumulate inc 0 sequence))

13
ex-2.34.scm Normal file
View file

@ -0,0 +1,13 @@
#lang sicp
(define (accumulate op initial sequence)
(if (null? sequence)
initial
(op (car sequence)
(accumulate op initial (cdr sequence)))))
(define (horner-eval x coefficient-sequence)
(accumulate (lambda (this-coeff higher-terms)
(+ (* higher-terms x) this-coeff))
0
coefficient-sequence))

14
ex-2.35.scm Normal file
View file

@ -0,0 +1,14 @@
#lang sicp
(define (accumulate op initial sequence)
(if (null? sequence)
initial
(op (car sequence)
(accumulate op initial (cdr sequence)))))
(define (count-leaves t)
(accumulate + 0 (map (lambda (sub-t)
(cond ((pair? sub-t) (count-leaves sub-t))
((null? sub-t) 0)
(else 1)))
t)))

13
ex-2.36.scm Normal file
View file

@ -0,0 +1,13 @@
#lang sicp
(define (accumulate op initial sequence)
(if (null? sequence)
initial
(op (car sequence)
(accumulate op initial (cdr sequence)))))
(define (accumulate-n op init seqs)
(if (null? (car seqs))
nil
(cons (accumulate op init (map car seqs))
(accumulate-n op init (map cdr seqs)))))

36
ex-2.37.scm Normal file
View file

@ -0,0 +1,36 @@
#lang sicp
;;;;
;; Error in the hexlet exercise: the matrix-*-vector line should say
;; m_ij*v_j not m_ij*v_i
;;;;
(define (accumulate op initial sequence)
(if (null? sequence)
initial
(op (car sequence)
(accumulate op initial (cdr sequence)))))
(define (accumulate-n op init seqs)
(if (null? (car seqs))
'()
(cons (accumulate op init (map car seqs))
(accumulate-n op init (map cdr seqs)))))
(define (dot-product v w)
(accumulate + 0 (map * v w)))
(define (matrix-*-vector m v)
(map (lambda (row)
(dot-product row v))
m))
(define (matrix-*-matrix m n)
(let ((cols (transpose n)))
(map (lambda (row-m)
(map (lambda (col)
(dot-product row-m col))
cols))
m)))
(define (transpose m)
(accumulate-n cons '() m))

22
ex-2.38.scm Normal file
View file

@ -0,0 +1,22 @@
#lang sicp
(define (fold-right op initial sequence)
(if (null? sequence)
initial
(op (car sequence)
(fold-right op initial (cdr sequence)))))
(define (fold-left op initial sequence)
(define (iter result rest)
(if (null? rest)
result
(iter (op result (car rest))
(cdr rest))))
(iter initial sequence))
; (fold-right / 1 (list 1 2 3)) -> (1/(2/(3/1))) = 3/2
; (fold-left / 1 (list 1 2 3)) -> (((1/1)/2)/3) = 1/6
; (fold-right list nil (list 1 2 3)) -> (1 (2 (3 ())))
; (fold-left list nil (list 1 2 3)) -> (((() 1) 2) 3)
; in order to produce the same results, the operation
; must be associative.

21
ex-2.39.scm Normal file
View file

@ -0,0 +1,21 @@
#lang sicp
(define (fold-right op initial sequence)
(if (null? sequence)
initial
(op (car sequence)
(fold-right op initial (cdr sequence)))))
(define (fold-left op initial sequence)
(define (iter result rest)
(if (null? rest)
result
(iter (op result (car rest))
(cdr rest))))
(iter initial sequence))
(define (reverse-right sequence)
(fold-right (lambda (x y) (append y (list x))) nil sequence))
(define (reverse-left sequence)
(fold-left (lambda (x y) (cons y x)) nil sequence))

55
ex-2.40.scm Normal file
View file

@ -0,0 +1,55 @@
#lang sicp
; a) Define unique-pairs
(define (accumulate op initial sequence)
(if (null? sequence)
initial
(op (car sequence)
(accumulate op initial (cdr sequence)))))
(define (flatmap proc seq)
(accumulate append nil (map proc seq)))
(define (enumerate-interval a b)
(if (> a b)
'()
(cons a (enumerate-interval (+ a 1) b))))
(define (unique-pairs n)
(flatmap (lambda (i)
(map (lambda (j) (list i j))
(enumerate-interval 1 (- i 1))))
(enumerate-interval 1 n)))
; b) use it to define prime-sum-pairs
(define (filter predicate sequence)
(cond ((null? sequence) nil)
((predicate (car sequence))
(cons (car sequence)
(filter predicate (cdr sequence))))
(else (filter predicate (cdr sequence)))))
(define (square x) (* x x))
(define (smallest-divisor n)
(find-divisor n 2))
(define (find-divisor n test-divisor)
(cond ((> (square test-divisor) n) n)
((divides? test-divisor n) test-divisor)
(else (find-divisor n (+ test-divisor 1)))))
(define (divides? a b)
(= (remainder b a) 0))
(define (prime? n)
(= n (smallest-divisor n)))
(define (prime-sum? pair)
(prime? (+ (car pair) (cadr pair))))
(define (prime-sum-pairs n)
(map (lambda (pair)
(list (car pair) (cadr pair) (+ (car pair)
(cadr pair))))
(filter prime-sum?
(unique-pairs n))))

40
ex-2.41.scm Normal file
View file

@ -0,0 +1,40 @@
#lang sicp
(define (accumulate op initial sequence)
(if (null? sequence)
initial
(op (car sequence)
(accumulate op initial (cdr sequence)))))
(define (flatmap proc seq)
(accumulate append nil (map proc seq)))
(define (filter predicate sequence)
(cond ((null? sequence) nil)
((predicate (car sequence))
(cons (car sequence)
(filter predicate (cdr sequence))))
(else (filter predicate (cdr sequence)))))
(define (enumerate-interval a b)
(if (> a b)
'()
(cons a (enumerate-interval (+ a 1) b))))
(define (sum l) (accumulate + 0 l))
; returns a function which checks given list for
; specific sum
(define (sum-is-num s)
(lambda (list)
(= (sum list) s)))
(define (ordered-triples-with-sum n s)
(filter (sum-is-num s)
(flatmap (lambda (i)
(flatmap (lambda (j)
(map (lambda (k)
(list i j k))
(enumerate-interval 1 (- j 1))))
(enumerate-interval 1 (- i 1))))
(enumerate-interval 1 n))))

71
ex-2.42.scm Normal file
View file

@ -0,0 +1,71 @@
#lang sicp
(define (accumulate op initial sequence)
(if (null? sequence)
initial
(op (car sequence)
(accumulate op initial (cdr sequence)))))
(define (flatmap proc seq)
(accumulate append nil (map proc seq)))
(define (filter predicate sequence)
(cond ((null? sequence) nil)
((predicate (car sequence))
(cons (car sequence)
(filter predicate (cdr sequence))))
(else (filter predicate (cdr sequence)))))
(define (enumerate-interval a b)
(if (> a b)
'()
(cons a (enumerate-interval (+ a 1) b))))
; the board will be implemented as a list, which will, in a reversed order, list
; the rows of the queens, who are sorted by columns, for example:
; (5 3 1 4) means there are four queens with coordinates:
; (1,4), (2,1), (3,3), (4,5)
; this implementation is mostly chosen because of its efficiency and ease of use
(define empty-board '())
; with this implementation, k is unnecessary
(define (adjoin-position new-row k rest-of-queens)
(cons new-row rest-of-queens))
(define (all-false lst)
(cond ((eq? lst '()) #t)
((not (car lst)) (all-false (cdr lst)))
(else #f)))
(define (diagonals-from-row row len)
(list (enumerate-interval (+ row 1) (+ row len))
(reverse (enumerate-interval (- row len) (- row 1)))))
; same here
(define (safe? k positions)
(let* ((first (car positions))
(rest (cdr positions))
(diags (diagonals-from-row first (length rest)))
(upper-diag (car diags))
(lower-diag (cadr diags))
(match-row (map (lambda (x) (= x first))
rest))
(match-diag1 (map = rest upper-diag))
(match-diag2 (map = rest lower-diag)))
(and (all-false match-row)
(all-false match-diag1)
(all-false match-diag2))))
(define (queens board-size)
(define (queen-cols k)
(if (= k 0)
(list empty-board)
(filter
(lambda (positions) (safe? k positions))
(flatmap
(lambda (rest-of-queens)
(map (lambda (new-row)
(adjoin-position new-row k rest-of-queens))
(enumerate-interval 1 board-size)))
(queen-cols (- k 1))))))
(queen-cols board-size))

62
ex-2.43.txt Normal file
View file

@ -0,0 +1,62 @@
The normal function presented here:
(define (queens board-size)
(define (queen-cols k)
(if (= k 0)
(list empty-board)
(filter
(lambda (positions) (safe? k positions))
(flatmap
(lambda (rest-of-queens)
(map (lambda (new-row)
(adjoin-position
new-row k rest-of-queens))
(enumerate-interval 1 board-size)))
(queen-cols (- k 1))))))
(queen-cols board-size))
gets executed in roughly the following way: Before any of the calls to filter
or flatmap are performed (queen-cols (- k 1)) will be run. This will happen
recursively, so it will recursively call until (queen-cols 0), which will
return a list with a single empty-board.
Then, in the (queens-col 1) call, eight new boards, each with a single queen,
will be returned, then in the (queens-col 2), 64 will be created, then
filtered, and so forth, each time we exit the current call in the stack, we
have already filtered the results of the previous call.
On the other hand Louis Reasoner's function looks like this:
(define (queens board-size)
(define (queen-cols k)
(if (= k 0)
(list empty-board)
(filter
(lambda (positions) (safe? k positions))
(flatmap
(lambda (new-row)
(map (lambda (rest-of-queens)
(adjoin-position new-row k rest-of-queens))
(queen-cols (- k 1))))
(enumerate-interval 1 board-size)))))
(queen-cols board-size))
And it first calls enumerate-interval, and generates a list of 8 numbers.
After that, each of these numbers get the outer lambda applied to them, which
then calls (queen-cols 7) eight times. It will then adjoin, and afterwards
filter the results. It should be noted, these sub-calls WILL generate filtered
lists of queens, it's not as if all possible cases will be generated, and only
then filtered, however, each of these recursive subcalls will generate a list
of (queen-cols (- k 1)) eight times, instead of once, and so on recursively.
In other words, for the older version of the function, the execution time T(n)
(assuming board-size is 8), is roughly equal to:
T(n) = T(n-1) + O(8*Q(n-1))
^adjoining and filtering ^
(Q(n-1) is length of result of (queen-cols n))
unraveling this we get: O(Q(n-1)+Q(n-2)+Q(n-3)+...+Q(0))
Whereas the new function's time looks like this:
T(n) = 8*T(n-1) + O(8*Q(n-1))
unraveling, we get, very roughly:
O(8*Q(n-1) + 8*8*Q(n-2) + ... + 8^8*Q(0))
I haven't tried to run the exact numbers, because it would involve learning
exactly what Q(0), ... ,Q(8) are, which I didn't care to do.