Often the same programming pattern will be used with a number of different
procedures. To express such patterns as concepts, we will need to construct
procedures that can accept procedures as arguments or return procedures as
values. Procedures that manipulate procedures are called high-order
procedures, they can serve as powerful abstraction mechanisms, vastly
increaseing the expressive power of our language.
Lambda
Using lambda to create anonymous functions:
(define (plus4 x) (+ x 4)) is equivalent to(define plus4 (lambda (x) (+ x 4)))
Using lambda(let) to create local variables
Sometimes we can use internal definitions to get the same effect as with let.
And in which cases we couldn't get the same effect?
Abstractions and first-class procedures
As programmers, we should be alert to oppotunities to identify the underlying
abstractions in our programs and to build upon then and generalize them to
create more powerful abstractions. This is not to say one should always write
programs in the most abstract way possible; expert programmers know how to
choose the level of abstraction appropriate to their task. But it's important
to be able to think in terms of these abstractions, so that we can be ready
to apply them in new contexts.
Exercises
1.29
Answer:
This is not very hard, just simply translate the simpson rule definition to code:
(define (simpson-rulefabn); still use 'define' since we haven't learned 'let' till now(define h(/ (- ba)n)); the procedure to compute 'yk', the helper method used by 'term'(define (yk)(f(+ a(* kh)))); get the 'next and 'term for the sum procedure(define (nextk)(+ k1))(define (termk)(* (cond ((or (= k1)(= kn))1)((even? k)2)((odd? k)4))(yk)))(/ (* h(sumterm0nextn))3))(define (sumtermanextb)(if (> ab)0(+ (terma)(sumterm(nexta)nextb))))(define (integralfabdx)(define (add-dxx)(+ xdx))(* (sumf(+ a(/ dx2.0))add-dxb)dx))(define (cubex)(* xxx))(simpson-rulecube01100.0)(simpson-rulecube011000.0)(integralcube010.01)(integralcube010.001);; the output:; 0.24999998999999987; 0.24999999999900027; 0.24998750000000042; 0.249999875000001
1.30
Answer:
Put both the recursive and iterative versions here to compare:
(define (producttermanextb)(if (> ab)1(* (terma)(productterm(nexta)nextb))))(define (product-itertermanextb)(define (itercurresult)(if (> curb)result(iter(nextcur)(* (termcur)result))))(itera1))(define (factorialn)(define (identityx)x)(productidentity1incn))(define (incx)(+ x1))(product(lambda (x)x)1(lambda (x)(+ x1))6)(product-iter(lambda (x)x)1(lambda (x)(+ x1))6)(factorial6)(factorial10)(product(lambda (x)(* xx))1(lambda (x)(+ x1))5)(product-iter(lambda (x)(* xx))1(lambda (x)(+ x1))5);; compute the approximations to PI using the formula:;; PI 2*4*4*6*6*8...;; -- = --------------;; 4 3*3*5*5*7*7...;; here, term is (2n/(2n + 1) * 2(n+1) /(2n + 1)), n = 1, 2, 3, ...(/(product-iter(lambda (n)(* (* 2n)(* 2(+ n1.0))))1inc50)(product-iter(lambda (n)(* (+ (* 2n)1.0)(+ (* 2n)1.0)))1inc50))
There might be better ways to translate the formula. The solution above the
is not veru accurate and if the upper bound is too large (say 100), it will
yield to 'nan+'.
1.32
Answer:
1234567891011121314151617181920212223242526
(define (accumulatecombinernull-valuetermanextb)(if (> ab)null-value(combiner(terma)(accumulatecombinernull-valueterm(nexta)nextb))))(define (accumulate-itercombinernull-valuetermanextb)(define (itercurresult)(if (> curb)result(iter(nextcur)(combiner(termcur)result))))(iteranull-value))(define (sumtermanextb); (accumulate + 0 term a next b))(accumulate-iter+0termanextb))(define (producttermanextb); (accumulate * 1 term a next b))(accumulate-iter*1termanextb))(sum(lambda (x)x)1(lambda (x)(+ x1))6)(product(lambda (x)x)1(lambda (x)(+ x1))6)(sum(lambda (x)(* xx))1(lambda (x)(+ x1))5)(product(lambda (x)(* xx))1(lambda (x)(+ x1))5)
(define (filtered-accumulatecombinernull-valuetermanextbfilter)(if (> ab)null-value(if (filtera)(combiner(terma)(filtered-accumulatecombinernull-valueterm(nexta)nextbfilter))(filtered-accumulatecombinernull-valueterm(nexta)nextbfilter))))(define (prime?n)(= n(smallest-divisorn)))(define (smallest-divisorn)(find-divisorn2))(define (find-divisorntest-divisor)(cond ((> (squaretest-divisor)n)n)((divides?test-divisorn)test-divisor)(else (find-divisorn(+ test-divisor1)))))(define (squarex)(* xx))(define (divides?ab)(= (remainder ba)0))(define (incx)(+ x1))(define (identityx)x); return a procedure Integer -> Boolean; that check if the given integer is relative prime with n(define (relative-prime?n)(define (fa)(= (gcd na)1))f)(define (gcd ab)(if (= b0)a(gcd b(remainder ab))))(filtered-accumulate+0square2inc10prime?)(filtered-accumulate*1identity1inc10(relative-prime?10))
1.34
Answer:
Apply (f f) with get (f 2), while tring to apply (f 2), error will be issued
since a procedure is expected but an integer parameter 2 is given.
1.35
Answer:
12345678910111213141516171819
(define tolerance0.00001)(define (fixed-pointffirst-guess)(define (close-enoughxy)(< (abs (- xy))tolerance))(define (tryguess)(let ((next(fguess)))(if (close-enoughnextguess)next(trynext))))(tryfirst-guess)); since the golden-ratio x satisfies that x^2 = x + 1(define (golden-ratio)(fixed-point(lambda (x)(+ 1(/ 1x)))1.0))(golden-ratio)
(define tolerance0.00001)(define (fixed-pointffirst-guess)(define (close-enoughxy)(< (abs (- xy))tolerance))(define (tryguess)(display "current guess is: ")(display guess)(newline)(let ((next(fguess)))(if (close-enoughnextguess)next(trynext))))(tryfirst-guess)); without average damping(fixed-point(lambda (x)(/ (log 1000)(log x)))2.0); output below:; current guess is: 2.0; current guess is: 9.965784284662087; current guess is: 3.004472209841214; current guess is: 6.279195757507157; current guess is: 3.759850702401539; current guess is: 5.215843784925895; current guess is: 4.182207192401397; current guess is: 4.8277650983445906; current guess is: 4.387593384662677; current guess is: 4.671250085763899; current guess is: 4.481403616895052; current guess is: 4.6053657460929; current guess is: 4.5230849678718865; current guess is: 4.577114682047341; current guess is: 4.541382480151454; current guess is: 4.564903245230833; current guess is: 4.549372679303342; current guess is: 4.559606491913287; current guess is: 4.552853875788271; current guess is: 4.557305529748263; current guess is: 4.554369064436181; current guess is: 4.556305311532999; current guess is: 4.555028263573554; current guess is: 4.555870396702851; current guess is: 4.555315001192079; current guess is: 4.5556812635433275; current guess is: 4.555439715736846; current guess is: 4.555599009998291; current guess is: 4.555493957531389; current guess is: 4.555563237292884; current guess is: 4.555517548417651; current guess is: 4.555547679306398; current guess is: 4.555527808516254; current guess is: 4.555540912917957; 4.555532270803653; with average damping(fixed-point(lambda (x)(/ (+ x(/ (log 1000)(log x)))2))2.0); output below:; current guess is: 2.0; current guess is: 5.9828921423310435; current guess is: 4.922168721308343; current guess is: 4.628224318195455; current guess is: 4.568346513136242; current guess is: 4.5577305909237005; current guess is: 4.555909809045131; current guess is: 4.555599411610624; current guess is: 4.5555465521473675; 4.555537551999825
; k-term finite continued fraction(define (cont-fracndk)(define (fraci)(if (= ik)(/ (ni)(di))(/ (ni)(+ (di)(frac(+ i1))))))(frac1))(define (cont-frac-iterndk)(define (iteriresult)(if (= i0)result(iter(- i1)(/ (ni)(+ (di)result)))))(iterk0)); k = 10 produce 0.6179775280898876(cont-frac(lambda (i)1.0)(lambda (i)1.0)10)(cont-frac-iter(lambda (i)1.0)(lambda (i)1.0)10); k = 11 produce 0.6180555555555556(cont-frac(lambda (i)1.0)(lambda (i)1.0)11)(cont-frac-iter(lambda (i)1.0)(lambda (i)1.0)11); TODO: implement a procedure to retry different k until the first; one that produce the value accurate to 4 decimal.
(define (average-dampf)(define (averageab)(/ (+ ab)2))(lambda (x)(averagex(fx))))(define (squarex)(* xx))(define tolerance0.00001)(define (fixed-pointffirst-guess)(define (close-enoughxy)(< (abs (- xy))tolerance))(define (tryguess)(let ((next(fguess)))(if (close-enoughnextguess)next(trynext))))(tryfirst-guess));; re-write the square-root procedure(define (sqrt x)(fixed-point(average-damp(lambda (y)(/ xy)))1.0));; cube root, similar with above(define (cube-rootx)(fixed-point(average-damp(lambda (y)(/ x(squarey))))1.0))(define dx0.00001)(define (derivg)(lambda (x)(/ (- (g(+ xdx))(gx))dx)))(define (cubex)(* xxx))(define (newton-transformg)(lambda (x)(- x(/ (gx)((derivg)x)))))(define (newton-methodgguess)(fixed-point(newton-transformg)guess))(define (cubicabc)(lambda (x)(+ (* xxx)(* a(squarex))(* bx)c))); zero of x^3 + x^2 + x + 1; should be -1(newton-method(cubic111)1.0)
1.41
Answer:
1234567891011121314
;; Note: it's a little confusing at first, 'double' is not apply the function;; 'f' and double the result, it's 'DOUBLE' the application of the function;; 'f'.(define (doublef)(lambda (x)(f(fx))))(define (incx)(+ x1))((doubleinc)1)(((doubledouble)inc)1); this will get 21(((double(doubledouble))inc)5)