ch1.
1.1 elements of programming
a. primitive expressions
b. means of combination
c. means of abstraction
1.1.1 expr
e.g. (+ 1 (* 2 3))
made of parenthese.
1.1.2 var
(define size 2) # define a var named size whose value is 2
1.1.3 evaluating combination
a. evaluate the subexpr of the combination
b. apply the procedure that is the value of leftmost subexpr to the arguments that is the value of other subexpr.
1.1.4 compound procedure
e.g. (define (square x) (* x x)) # is the syntatic sugar of the following sentence
(define square (lamba (x) (* x x)))
formal: (define (<name> <formal params>) <body>)
*NOTE: diff : (define A (* 5 5)) # var
(define (B) (* 5 5)) # procedure without params
1.1.5 the substitution model for procedure application
prerequisite: (define (sum-of-squares x y) (+ (square x) (square y)))
process when interpreting the meaning of (sum-of-squares 2 3)
a. (sum-of-squares 2 3) -> (+ (square x) (square y))
b. (+ (square x) (square y)) -> (+ (square 2) (square 3))
c. (+ (square 2) (square 3)) -> (+ (* 2 2) (* 3 3))
d. do the calculation
** applicative order vs. normal order **
app order -> stated above(Lisp use this order)
normal order -> do not evaluate the subexpr until the whole expr contains only the primitive operator(not very efficient)
1.1.6 cond expr and predicate
(cond (<p1> <e1>)
(<p2> <e2>)
....
(<pn> <en>))
pn is called the predicate which is the procedure that returns true of false or the expr that is evaluated to true or false.
(define (abs x)
(cond ((< x 0) (- x))
(else x)))
if expr -> (if <predicate> <consequent> <alternative>)
logic operators -> (and <e1> ... <en>)
(or <e1> ... <en>)
(not <e>)
1.1.8 local name
bound variable <-> free variable
a procedure's meaning will not change if its bound variables change names.
block structure: internally defines the procedures in the calling procedure.
(define (sqrt x)
(define (good-enough? guess x)
(< (abs (- (square guess) x)) 0.001))
(define (improve guess x)
(average guess (/ x guess)))
(define (sqrt-iter guess x)
(if (good-enough? guess x)
guess
(sqrt-iter (improve guess x) x)))
(sqrt-iter 1.0 x))
*NOTE: the internal definitions must come first in the procedure's body.
tail recursive: execute the iterative process in constant space even
if the process is described in recursive procedure(Lisp).
linearly recursive: the amount of information(memory) needed to keep
track of recursion is linear to n.
exercise 1.9: (+ 4 5)
1.
(define (+ a b)
(if (= a 0)
b
(inc (+ (dec a) b))))
ans: recursive
(+ 4 5)
(inc (+ 3 5))
(inc (inc (+ 2 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
2.
(define (+ a b)
(if (= a 0)
b
(+ (dec a) (inc b))))
ans: iterative
(+ 4 5)
(+ 3 6)
(+ 2 7)
(+ 1 8)
(+ 0 9)
9
exercise 1.10
1. (A 1 10)
(A 0 (A 1 9))
(A 0 (A 0 (A 1 8)))
(A 0 (A 0 (A 0 (A 1 7))))
...
(A 0 (A 0 ... (A 1 1) ... )
-> 2^10 = 1024
2. (A 2 4)
(A 1 (A 2 3))
(A 1 (A 1 (A 2 2)))
(A 1 (A 1 (A 1 (A 2 1))))
(A 1 (A 1 (A 1 2)))
(A 1 (A 1 (A 0 (A 1 1))))
(A 1 (A 1 (A 0 2)))
(A 1 (A 1 4))
(A 1 16)
-> 2^16 = 1024 * 64
3. (A 3 3)
(A 2 (A 3 2))
(A 2 (A 2 (A 3 1)))
(A 2 (A 2 2))
(A 2 (A 1 (A 2 1)))
(A 2 (A 1 2))
(A 2 (A 0 (A 1 1)))
(A 2 (A 0 2))
(A 2 4)
-> 2^16 = 1024 * 64
(define (f n) (A 0 n))
f(n) = 2n
(define (g n) (A 1 n))
g(n) = 2^n
(define (h n) (A 2 n))
h(n) = 2^h(n-1) when n > 1
h(n) = 2 when n = 1
h(n) = 0 when n = 0
exercise 1.11:
recursion:
(define (f n)
(if (< n 3)
n
(+ (f (- n 1))
(* 2 (f (- n 2)))
(* 3 (f (- n 3))))))
iterative:
(define (f n) (f-iter 2 1 0 n))
(define (f-iter a b c count)
(if (= count 0)
c
(f-iter (+ a (* 2 b) (* 3 c)) a b (- count 1))))
exercise 1.12:
Pascal's trianle:
(define (pascal m n)
(if (or (= m 1) (= m n))
1
(+ (pascal (- m 1) (- n 1))
(pascal m (- n 1)))))
exercise 1.16:
(define (expt-cal base expt)
(expt-iter base expt 1))
(define (expt-iter base expt a)
(cond ((= expt 0) a)
((even? expt) (expt-iter (square base) (/ expt 2) a))
(else (expt-iter base (- expt 1) (* a base)))))
(define (even? num)
(= (remainder num 2) 0))
*** NOTE: In general, the technique of defining an invariant quantity that
remains unchanged from state to state is a powerful way to think about the design of iterative
algorithms.
In this exercise, the invariant quantity is a * b^n
exercise: 1.17:
(define (f-mul a b)
(if (< b 0)
(fast-mul (- 0 a) (- 0 b))
(fast-mul a b)))
(define (fast-mul a b)
(cond ((= b 0) 0)
((even? b) (double (fast-mul a (halve b))))
(else (+ a (fast-mul a (- b 1))))))
exercise 1.18:
invariant quantity: a x b + c
(define (f-mul-iter a b)
(fast-mul-iter a b 0))
(define (fast-mul-iter a b c)
(cond ((= b 0) c)
((even? b) (fast-mul-iter (double a) (halve b) c))
(else (fast-mul-iter a (- b 1) (+ c a)))))
exercise 1.19:
p' = p^2 + q^2
q' = q^2 + 2pq
(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
(sos p q)
(+ (square q) (double (* p q)))
(/ count 2)))
(else (fib-iter (+ (* b q) (* a q) (* a p))
(+ (* b p) (* a q))
p
q
(- count 1)))))
T = [1, 1; 1, 0]
exercise 1.20:
normal order:
(gcd 206 40)
(if (= 40 0) ...)
(gcd 40 (remainder 206 40))
(if (= (remainder 206 40) 0) ...)
(if (= 6 0) ...)
(gcd (remainder 206 40) (remainder 40 (remainder 206 40)))
(if (= (remainder 40 (remainder 206 40)) 0) ...)
(if (= 4 0) ...)
(gcd (remainder 40 (remainder 206 40)) (remainder (remainder 206 40) (remainder 40 (remainder 206 40))))
(if (= (remainder (remainder 206 40) (remainder 40 (remainder 206 40))) 0) ...)
(if (= 2 0) ...)
(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)))))
(if (= (remainder (remainder 40 (remainder 206 40)) (remainder (remainder 206 40) (remainder 40 (remainder 206 40)))) 0) ...)
(if (= 0 0) ...)
(remainder (remainder 206 40) (remainder 40 (remainder 206 40)))
**NOTE: in the body of if expr, first uses normal order to substitute
all params in it, then begin to evaluate.
applicative order:
(gcd 206 40)
(gcd 40 (remainder 206 40))
(gcd 40 6)
(gcd 6 (remainder 40 6))
(gcd 6 4)
(gcd 4 (remainder 6 4))
(gcd 4 2)
(gcd 2 (remainder 4 2))
(gcd 2 0)
2
exercise 1.21:
(smallest-divisor 199) -> 199
(smallest-divisor 1999) -> 1999
(smallest-divisor 19999) -> 7
exercise 1.22:
(define (timed-prime-test 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)
(newline)
(display n)
(display " *** ")
(display elapsed-time))
exercise 1.22:
(define (search-for-primes begin end)
(cond ((even? begin) (search-for-primes (+ begin 1) end))
((> begin end) (display " done "))
(else (timed-prime-test begin)
(search-for-primes (+ 1 begin) end))))
exercise 1.25:
The simplified version will be slower than the version mentioned
before, because the multiplication will involve large numbers.
exercise 1.26:
(define (expmod base exp m)
(cond ((= exp 0) 1)
((even? exp)
(remainder (* (expmod base (/ exp 2) m)
(expmod base (/ exp 2) m))
m))
(else
(remainder (* base (expmod base (- exp 1) m))
m))))
The original version: n -> (n/2)
The new version: n -> 2*(n/2) = n
exercise 1.27:
(define (cong-test n)
(define (cong-test-iter a n)
(cond ((< a 2) true)
((= (expmod a n n) a) (cong-test-iter (- a 1) n))
(else false)))
(cong-test-iter (- n 1) n))
exercise 1.28:
origin:
(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))))
modified:
(define (expmod-mr base exp m)
(cond ((= exp 0) 1)
((even? exp)
(if (or (= (expmod-mr base (/ exp 2) m) 1)
(= (expmod-mr base (/ exp 2) m) (- n 1))
(> (remainder (square (expmod-mr base (/ exp 2) m) m)) 1))
(remainder (square (expmod-mr base (/ exp 2) m) m))
0))
(else
(remainder (* base (expmod-mr base (- exp 1) m))
m))))
a more efficient version:
(define (miller-rabin-expmod base exp m)
(define (squaremod-with-check x)
(define (check-nontrivial-sqrt1 x square)
(if (and (= square 1)
(not (= x 1))
(not (= x (- m 1))))
0
square))
(check-nontrivial-sqrt1 x (remainder (square x) m)))
(cond ((= exp 0) 1)
((even? exp) (squaremod-with-check
(miller-rabin-expmod base (/ exp 2) m)))
(else
(remainder (* base (miller-rabin-expmod base (- exp 1) m))
m))))
**NOTE: when considering using variable, it's time to define a
procefure whose scope equals the scope of the variable you want to create.
1.3 Procedures as args
(define (sum term a next b)
(if (> a b)
0
(+ (term a)
(sum term (next a) next b))))
where <term> and <next> is the argument representing procedures.
exercise 1.29: (Simpson's Rule)
(define (integral f a b dx)
(define (add-dx x) (+ x dx))
(* (sum f (+ a (/ dx 2.0)) add-dx b)
dx))
Simpson's Rule:
(define (simpson f a b n)
(define h (/ (- a b) n))
(define (param h)
(cond ((= (remainder h n) 0) 1)
((even? h) 2)
(else 4)))
(define (term i)
(* (param i) (f (+ a (* i h)))))
(define (next i) (+ i 1))
(* (sum term 0 next n)
(/ h 3)))
exercise 1.30:
(define (sum term a next b)
(define (iter a result)
(if (> a b)
result
(iter (next a) (+ result (term a)))))
(iter a 0))
exercise 1.31:
recursive:
(define (product term a next b)
(if (> a b)
1
(* (product term (next a) next b)
(term a))))
factorial:
(define (factorial n)
(product (lambda (x) x)
1 1+ n))
pi/4:
(define (pi4 n)
(define (factor x)
(/ (* x (+ x 2.0)) (square (+ x 1))))
(define (term i)
(factor (* i 2)))
(product term 1 1+ n))
;; change 2 to 2.0 in factor because the output will be rational number
if using 2.
b. iterative product
(define (product term a next b)
(define (iter a result)
(if (> a b)
result
(iter (next a) (* result (term a)))))
(iter a 1))
exercise 1.32:
a.
(define (accumulate combiner null-value term a next b)
(if (> a b)
null-value
(combiner (term a)
(accumulate combiner
null-value
term
(next a)
next
b))))
(define (sum term a next b)
(accumulate + 0 term a next b))
(define (product term a next b)
(accumulate * 1 term a next b))
b.
iterative:
(define (accumulate combiner null-value term a next b)
(define (iter a result)
(if (> a b)
result
(iter (next a) (combiner (term a) result))))
(iter a null-value))
exercise 1.33:
(define (filtered-accumulate combiner null-value filter term a next b)
(cond ((> a b) null-value)
((filter a) (combiner (term a)
(accumulate combiner
null-value
filter
term
(next a)
next
b)))
(else (accumulate combiner null-value filter term
a next b))))
a.
(define (sum-of-sq filter a b)
(filtered-accumulate + 0 filter square a 1+ b))
(define (sq-of-prime a b)
(sum-of-sq prime? a b))
b.
(define (prod-of-rel-prime n)
(define (rel-prime? a b)
(= (gcd a b) 1))
(accumulate * 1 rel-prime? identity 1 1+ (- n 1)))
1.3.2 lambda expr
(lambda (<formal-params>) <body>)
let expr to create local vars
The original expr:
(define (f x y)
((lambda (a b)
(+ (* x (square a))
(* y b)
(* a b)))
(+ 1 (* x y))
(- 1 y)))
syntatic sugar:
(define (f x y)
(let ((a (+ 1 (* x y)))
(b (- 1 y)))
(+ (* x (square a))
(* y b)
(* a b))))
(let ((<var1> <exp1>)
(<var2> <exp2>)
(<varn> <expn>))
<body>)
is equivalent to:
((lambda (<var1> ...<varn>)
<body>)
<exp1>
<expn>)
NOTES:
1. the variables in the <body> will apply the value as local as possible.
e.g. (+ (let ((x 3))
(+ x (* x 10)))
x)
ans = 38
2. the values assigned to vars in let is computed outside let expr.
x = 2:
(let ((x 3)
(y (+ x 2)))
(* x y))
ans = 12
exercise 1.34:
error:
the final display will be like:
((lambda (g) (g 2)) 2)
where the lambda expr is supposed take a procedure as argument.
1.3.3 procedure as general methods
finding fixed-point of a function
y = x / y -> 2y = y + x/y -> y = (y + x/y)/2
this technique is called average damping.
(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))
exercise 1.35:
phi = (1+sqrt(5))/2
(define golden-rate
(fixed-point (lambda (x) (+ 1 (/ 1 x))) 1.0))
exercise 1.36:
(define (fixed-point f first-guess)
(define (close-enough? v1 v2)
(< (abs (- v1 v2)) tolerance))
(define (try guess)
(let ((next (f guess)))
(display "guess ")
(display guess) (newline)
(if (close-enough? guess next)
next
(try next))))
(try first-guess))
;; because I define golden-rate as a value-variable, if typing "golden-rate" merely it will output the value without any output. But if evaluating the definition of golden-rate, the display and value will appear.
a. without average-damping:
(define log1000 (log 1000))
(fixed-point (lambda (x) (/ log1000 (log x)))
2.0)
b. with average-damping
(fixed-point (lambda (x) (average x (/ log1000 (log x))))
2.0)
;; with average-damping, the fixed-point uses much less steps to calculate the root.
exercise 1.37:
(define (cont-frac n d k)
(define (cont-helper i)
(if (= i k)
(/ (n i) (d i))
(/ (n i) (+ (d i) (cont-helper (1+ i))))))
(cont-helper 1))
iterative:
(define (cont-frac n d k)
(define (iter i result)
(if (= i 0)
result
(iter (-1+ i) (/ (n i) (+ (d i) result)))))
(iter k 0))
exercise 1.38:
(define (n x) 1.0)
(define (d x)
(let ((a (remainder x 3))
(b (/ (1+ x) 3)))
(if (= a 2)
(* 2 b)
1.0)))
(define e-2 (cont-frac n d 10000))
exercise 1.39:
(define (tan-cf x k)
(define (n i)
(if (= i 1)
x
(square x)))
(define (d i) (- (* 2 i) 1))
(Cont-frac n d k))
1.3.4 Precodures as Returned values
average damping: given a function f, consider the function whose value at x is equal to the average of x and f(x).
derivative function of g:
(define (deriv g)
(lambda (x)
(/ (- (g (+ x dx)) (g x))
dx)))
(define (deriv g)
(lambda (x)
(/ (- (g (+ x dx)) (g x))
dx)))
(define (newton-transform g)
(lambda (x)
(- x (/ (g x) ((deriv g) x)))))
(define (newtons-method g guess)
(fixed-point (newton-transform g) guess))
first class status: elements with the fewest restrictions are said to have first class status.
a. they may be named by variables.
b. they may be passed as arguments to procedures.
c. they may be returned as the results of procedures.
d. they may be included in data structures.
exercise 1.40:
(define (cube x) (* x x x))
(define (cubic a b c)
(lambda (x) (+ (cube x) (* a (square x)) (* b x) c)))
exercise 1.41:
(define (double f)
(lambda (x) (f (f x))))
;; ans = 21
;; because double applies its arg twice, (double double) applies it arg 4 times, and (double (double double)) applies its arg 16 times. So the answer is (+ 5 16)
exercise 1.42:
(define (compose f g)
(lambda (x) (f (g x))))
exercise 1.43:
(define (repeated f n)
(define (iter g i)
(if (= i 1)
g
(iter (compose f g) (-1+ i))))
(iter f n))
;; cannot use a O(log(n)) version.
exercise 1.44:
(define (smooth f)
(lambda (x) (average3 (f (+ x dx)) (f x) (f (- x dx)))))
(define (n-fold-smooth f n)
(repeated (smooth f) n))
exercise 1.45:
(define (pow x y)
(define (mul a)
(* a x))
((repeated mul y) 1))
(define (floor x)
(define (iter n)
(if (> n x)
(-1+ n)
(iter (1+ n))))
(iter 0))
(define (nth-root x n)
(define (log2 n)
(/ (log n) (log 2)))
(let ((k (floor (log2 n))))
(fixed-point ((repeated average-damp k) (lambda (y)
(/ x (pow y (-1+ n)))))
1.0)))
exercise 1.46:
(define (iterative-improve good-enf? improve)
(lambda (x)
(define (iter a)
(let ((next (improve a)))
(if (good-enf? a next)
next
(iter next))))
(iter x)))
sqrt:
(define (sqrt x1)
(let ((good-enf? (lambda (a b) (< (abs (- a b)) 0.001)))
(improve (lambda (guess) (average guess (/ x1 guess)))))
((iterative-improve good-enf? improve) 1.0)))
fixed-point:
(define (fixed-point f first-guess)
(define (close-enough? v1 v2)
(< (abs (- v1 v2)) tolerance))
(define (improve a) (f a))
((iterative-improve close-enough? improve) first-guess))