advantage of prefix notation:
1. take an arbitrary number of argument
> (+ 21 34 12 7) 742. it extends in a straight forward way to allow combinations to be nested
> (+ (* 3 5) (- 10 6)) 19
we use define to name things:
> (define radius 10) > (* pi (* radius radius)) 314.1592653589793 > (define circumference (* 2 pi radius)) > circumference 62.83185307179586
evaluating combinations by two steps:
powerful elements:
1. Numbers and arithmetic operations are primitive data and procedures.
(define (<name> <formal parameters>) <body>)the good example is:
(define (square x) (* x x)) (define (sum-of-squares x y) (+ (square x) (square y))) ;25 (sum-of-squares 3 4)
The application process is as follows:
To apply a compound procedure to arguments, evaluate the body of the procedure with each formal parameter replaced by the corresponding argument.
so, (sum-of-squares 3 4) first to be:
(sum-of-squares 3 4) -> (+ (square 3) (square 4)) -> (+ (* 3 3) (* 4 4)) -> (+ 9 16) -> 25The process we have just described is called the substitution model, also called applicative-order evaluation.
but there has another evaluation: normal-order evaluation.
(define (square x) (* x x)) (define (sum-of-squares x y) (+ (square x) (square y))) (define (f a) (sum-of-squares (+ a 1) (* a 2))) ;normal-order evaluation (sum-of-squares (+ 5 1) (* 5 2)) -> (+ (square (+ 5 1)) (square (* 5 2))) -> (+ (* (+ 5 1) (+ 5 1)) (* (* 5 2) (* 5 2))) -> (+ (* 6 6) (* 10 10)) -> (+ 36 100) -> 136 ;applicative-order evaluation (sum-of-squares (+ 5 1) (* 5 2)) -> (+ (square 6) (square 10)) -> (+ (* 6 6) (* 10 10)) -> (+ 36 100) -> 136LISP use applicative-order evaluation.
conditional expression is:
(cond (<p1> <e1>) (<p2> <e2>) ... (<pn> <en>)) (cond (<p1> <e1> (<p2> <e2>) ... (<pn> <en>) (else <e>))) (if <predicate> <consequent> <alternative>)if we want to accumulate the abs,we could write:
(define (abs x) (cond ((> x 0) x) ((= x 0) 0) ((< x 0) (- x)))) ;better use else (define (abs x) (cond ((< x 0) (- x)) (else x))) ;also use if (define (abs x) (if (< x 0) (- x) x))we could use “and”, “or”, “not” to judge the condition.
1.1.7 Example:Square Roots by Newton’s Method
how could we accumulate the square-root:
we could use Newton’s method of successive approximations, which says that whenever we have a guess y for the value of the square root of a number x, we can perform a simple manipulation to get a better guess(one closer to the actual square root) by averaging y with x/y. For example:
we could write LISP code:
(define (sqrt-iter guess x) (if (good-enough? guess x) guess (sqrt-iter (improve guess x) x))) (define (improve guess x) (average guess (/ x guess))) (define (average x y) (/ (+ x y) 2)) (define (good-enough? guess x) (< (abs (- (square guess) x)) 0.001)) (define (square x) (* x x)) (define (new-sqrt x) (sqrt-iter 1.0 x)) ;3.00009155413138 (new-sqrt 9) ;11.704699917758145 (new-sqrt 137)
Local names:
A formal parameter of a procedure has a very special role in the procedure definition, in that it doesn’t matter what name the formal parameter has. Such a name in called a bound variable, and we say that the procedure definition binds its formal parameters. The meaning of a procedure definition is unchanged if a bound variable is consistently renamed throughout the definition. If a variable is not bound, we say that it is free. The set of expressions for which a binding defines a name is called the scope of that name. In a procedure definition, the bound variables declared as the formal parameters of the procedure have the body of the procedure as their scope.
Internal definitions and block structure:
the sqrt function has a problem that: like good-enough?, improve and sqrt-iter function, it only be using for sqrt, not for others. so we could define them in internal:
(define (new-sqrt x) (define (square x) (* x x)) (define (good-enough? guess x) (< (abs (- (square guess) x)) 0.001)) (define (average x y) (/ (+ x y) 2)) (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)) ;3.00009155413138 (new-sqrt 9) ;11.704699917758145 (new-sqrt 137)this call block structure.
because the x will not be changed, we also write like that:
(define (new-sqrt x) (define (square x) (* x x)) (define (good-enough? guess) (< (abs (- (square guess) x)) 0.001)) (define (average x y) (/ (+ x y) 2)) (define (improve guess) (average guess (/ x guess))) (define (sqrt-iter guess) (if (good-enough? guess) guess (sqrt-iter (improve guess)))) (sqrt-iter 1.0)) ;3.00009155413138 (new-sqrt 9) ;11.704699917758145 (new-sqrt 137)
when we considering the factorial function:
n! = n · (n − 1) · (n − 2) · · · 3 · 2 · 1.we have two method. one is recursion, we could write like that:
n! = n · [(n − 1) · (n − 2) · · · 3 · 2 · 1] = n · (n − 1)!so the lisp code like that:
(define (factorial n) (if (= n 1) 1 (* n (factorial (- n 1))))) ;120 (factorial 5)and we could use iteration.
(define (factorial n)
(define (iter-factorial product counter)
(if (> counter n)
product
(iter-factorial (* product counter)
(+ counter 1))))
(iter-factorial 1 1))
;120
(factorial 5)
we could write the Fibonacci:
then we write the lisp code:
(define (fib n) (cond ((= n 0) 0) ((= n 1) 1) (else (+ (fib (- n 1)) (fib (- n 2)))))) ;55 (fib 10)
it’s a tree recursion, like that:
we could also write it in iteration:
(define (fib-recursive n) (define (iter-fib a b count) (if (= count n) a (iter-fib b (+ a b) (+ count 1)))) (iter-fib 0 1 0)) ;55 (fib-recursive 10)
Example: Counting change
(define (count-change amount) (cc amount 5)) (define (cc amount kinds-of-coins) (cond ;amount == 0,1 method ((= amount 0) 1) ((or (< amount 0) (= kinds-of-coins 0)) 0) (else (+ ;the number of ways to change amount using all but the ;first kind of coin(kinds-of-coins - 1) (cc amount (- kinds-of-coins 1)) ;the number of ways to change amount - the value of kinds-of-coins (cc (- amount (first-denomination kinds-of-coins)) kinds-of-coins))))) (define (first-denomination kinds-of-coins) (cond ((= kinds-of-coins 1) 1) ((= kinds-of-coins 2) 5) ((= kinds-of-coins 3) 10) ((= kinds-of-coins 4) 25) ((= kinds-of-coins 5) 50))) ;292 (count-change 100)
the question is: when x is small, sin x == x. so we accumulate the sin x = 3sin(x / 3) - 4sin^3(x / 3):
(define (cube x) (* x x x)) (define (p x) (- (* 3 x) (* 4 (cube x)))) (define (sine angle) (if (not (> (abs angle) 0.1)) angle (p (sine (/ angle 3.0))))) (sine 12.15) -> (p (sine 405 / 100)) -> (p (p (sine 135 / 100))) -> (p (p (p (sine 45 / 100)))) -> (p (p (p (p (sine 15 / 100))))) -> (p (p (p (p (p (sine 5 / 100)))))) -> (p (p (p (p (p 0.05)))))
(define (expt-recursive b n) (if (= n 0) 1 (* b (expt-recursive b (- n 1))))) (define (expt-iteractive b n) (define (iter-expt index product) (if (= index n) product (iter-expt (+ index 1) (* product b)))) (iter-expt 1 b)) ;1024 (expt-recursive 2 10) ;1024 (expt-iteractive 2 10)
(define (square x) (* x x)) (define (fast-expt b n) (cond ((= n 0) 1) ((even? n) (square (fast-expt b (/ n 2)))) (else (* b (fast-expt b (- n 1)))))) ;1024 (fast-expt 2 10)
GCD(a, b) = GCD(b, r), r = a % b. so the code like that:
(define (gcd-recursive a b) (if (= b 0) a (gcd-recursive b (remainder a b)))) ;4 (gcd-recursive 204 40)
Searching for divisors
we could use the stupid method to find the prime:
(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 (square x) (* x x)) (define (prime? n) (= n (smallest-divisor n))) ;#t (prime? 101) ;#f (prime? 99)The Fermat test
(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 (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))) ;#t (fast-prime? 101 3) ;#f (fast-prime? 99 3)
consider the following three procedures:
(define (sum-integers a b) (if (> a b) 0 (+ a (sum-integers (+ a 1) b)))) (define (sum-cubes a b) (if (> a b) 0 (+ (cube a) (sum-cubes (+ a 1) b)))) (define (pi-sum a b) (if (> a b) 0 (+ (/ 1.0 (* a (+ a 2))) (pi-sum (+ a 4) b))))the three procedures have the same template:
(define (<name> a b) (if (> a b) 0 (+ (<term> a) (<name> (<next> a) b))))there has a math concept:
so we now could write our code:
(define (sum term a next b) (if (> a b) 0 (+ (term a) (sum term (next a) next b)))) (define (inc n) (+ n 1)) (define (cube x) (* x x x)) (define (sum-cubes a b) (sum cube a inc b)) ;3025 (sum-cubes 1 10) (define (sum-integers a b) (sum identity a inc b)) ;55 (sum-integers 1 10) (define (pi-sum a b) (define (pi-term x) (/ 1.0 (* x (+ x 2)))) (define (pi-next x) (+ x 4)) (sum pi-term a pi-next b)) ;3.141392653591793 (* 8 (pi-sum 1 10000))we could also write below method:
the code is:
(define (sum term a next b) (if (> a b) 0 (+ (term a) (sum term (next a) next b)))) (define (integral f a b dx) (define (add-dx x) (+ x dx)) (* (sum f (+ a (/ dx 2.0)) add-dx b) dx)) (define (cube x) (* x x x)) ;0.24998750000000042 (integral cube 0 1 0.01) ;0.249999875000001 (integral cube 0 1 0.001)
lambda define that:
(lambda (<formal-paramters>) <body>)so:
(define (plus4 x) (+ x 4)) -> (define plus4 (lambda (x) (+ x 4)))Using let to create local variables
if we accumulate:
so we first must write like that:
(define (f x y) (define (f-helper a b) (+ (* x (square a b)) (* y b) (* a b))) (f-helper (+ 1 (* x y)) (- 1 y)))but we learn the lambda, we could write like that:
(define (f x y) ((lambda (a b) (+ (* (square a)) (* y b) (* a b))) (+ 1 (* x y)) (- 1 y)))but the best method is to use let:
(define (f x y) (let ((a (+ 1 (* x y))) (b (- 1 y))) (+ (* x (square a)) (* y b) (* a b))))let define that:
and it is a syntactic sugar for the lambda:
there has two way to notice the let:
1. let allows one to bind variables as locally as possible to where they are to be used. For example, if the value of x is 5, the value of the expression:
(+ (let ((x 3)) (+ x (* x 10))) x)
(let ((x 3) (y (+ x 2))) (* x y))will have the value 12 because, inside the body of the let, x will be 3, and y will be 4 = 2 + 2.
the half-interval method use to find roots make f(x) = 0.
(define (average x y) (/ (+ x y) 2.0)) (define (search f neg-point pos-point) (let ((midpoint (average neg-point pos-point))) (if (close-enough? neg-point pos-point) midpoint (let ((test-value (f midpoint))) (cond ((positive? test-value) (search f neg-point midpoint)) ((negative? test-value) (search f midpoint pos-point)) (else midpoint)))))) (define (close-enough? x y) (< (abs (- x y)) 0.01)) (define (half-interval-method f a b) (let ((a-value (f a)) (b-value (f b))) (cond ((and (negative? a-value) (positive? b-value)) (search f a b)) ((and (negative? b-value) (positive? a-value)) (search f b a)) (else (error "Values are not of opposite sign" a b))))) ;3.14453125 (half-interval-method sin 2.0 4.0)
(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)) ;0.7390822985224023 (fixed-point cos 1.0)when we accumulate y^2 = x, we could use y = x / y, and define the function:
(define (sqrt x) (fixed-point (lambda (y) (/ x y)) 1.0))
(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 (average x y) (/ (+ x y) 2)) (define (sqrt-new x) (fixed-point (lambda (y) (average y (/ x y))) 1.0)) ;3.3166247903554 (sqrt-new 11)
1.3.4 Procedures as Returned Values
we use the average to accumulate the y = x ^ 2, we could also use:
(define (average-damp f) (lambda (x) (average x (f x))))
(define (sqrt x) (fixed-point (average-damp (lambda (y) (/ x y))) 1.0))Newton’s method
for the method:
when g(x) = 0, x->f(x). so that is why when g(x) = y^2 - x = 0, we could accumulate sqrt x.
but we first accumulate the Dg(x):
we could write the code:
(define (deriv g) (lambda (x) (/ (- (g (+ x dx)) (g x)) dx))) (define dx 0.00001)
(define (deriv g) (lambda (x) (/ (- (g (+ x dx)) (g x)) dx))) (define dx 0.00001) (define (newton-transform g) (lambda (x) (- x (/ (g x) ((deriv g) x))))) (define (newtons-method g guess) (fixed-point (newton-transform g) guess)) (define (square x) (* x x)) (define (sqrt-new x) (newtons-method (lambda (y) (- (square y) x)) 1.0)) (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)) ;3.316624790355423 (sqrt-new 11)