标签:scheme recursion lisp sicp procedure
To know more about programming, I have decided to start reading the famous Structure and Interpretation of Computer Programs (SICP, or the Wizard Book), which is first published by MIT in 1985. The Wizard Book used MIT Scheme, which is a dialect of Lisp, as the demonstrating language. This language is so different from the languages I know (C++ and JavaScript, which are both inspired by C). However, the book does not talk much about the characteristics of the language. It focus on teaching important concepts in Computer Science, but not teaching a particular language. I am sure that the book and the interesting language can help me to become a better programmer! (but not just a coder XD) This book is available online under Creative Common (CC) so you may take a look at it too!
In this exercise, I only need to write down the result of each expression. I have put a semi-colon(;) before the result.
10 ;10 (+ 5 3 4) ;12 (- 9 1) ;8 (/ 6 2) ;3 (+ (* 2 4) (- 4 6)) ;6 (define a 3) (define b (+ a 1)) (+ a b (* a b)) ;19 (= a b) ;#f (if (and (> b a) (< b (* a b))) b a) ;4 (cond ((= a 4) 6) ((= b 4) (+ 6 7 a)) (else 25)) ;16 (+ 2 (if (> b a) b a)) ;6 (* (cond ((> a b) a) ((< a b) b) (else -1)) (+ a 1) ;16
In this exercise, I need to translate a mathematical expression into a complex combination in Scheme.
(/ (+ 5 4 (- 2 (- 3 (+ 6 (/ 4 3))))) (* 3 (- 6 2) (- 2 7)))(well, I have abused the use of indentation in this exercise...)
In this exercise, I need to write a procedure that take three numbers as arguments and returns the sum of the squares of the two larger numbers.
(define (sum-of-squares-of-larger-two a b c) (cond ((and (<= a b) (<= a c)) (+ (* b b) (* c c))) ((and (<= b a) (<= b c)) (+ (* a a) (* c c))) (else (+ (* a a) (* b b)))))
In this exercise, I need to explain the behaviour of the following procedure:
(define (a-plus-abs-b a b) ((if (> b 0) + -) a b))This procedure returns the sum of a and the absolute value of b.
When b is positive, the procedure return a+b.
When b is 0 or negative, the procedure returns a-b (a-b = a-(-|b|) = a+|b|, given b<=0)
Given the following code, is the result different when applicative order and normal order are used?
(define (p) (p)) (define (test x y) (if (= x 0) 0 y)) (test 0 (p))
(test 0 (p))
This method would first evaluate all the subexpressions of the combination.
(p) calls (p) again so there is an infinite loop. (runtime_error)
(test 0 (p))
(if (= 0 0) 0 (p))
0
This method would first substitute operand expressions for parameters until it obtained an expression involving only primitive operators, and would then perform the evaluation. (p) is not evaluated until it is needed, so no infinite loop appears. (0 is returned)
Why the built-in if is a special form instead of a procedure? Given the following definition of a new-if:
(define (new-if predicate then-clause else-clause) (cond (predicate then-clause) (else else-clause)))This new-if looks pretty good when applying to simple cases. However, it is not that good when recursion is used in the clauses. Consider this:
(define (sqrt-iter guess x) (new-if (good-enough? guess x) guess (sqrt-iter (improve guess x) x)))Since the interpreter evaluate combinations in applicative order, it would evaluate all the subexpressions in (new-if predicate then-clause else-clause). As the else-clause of new-if in sqrt-iter is sqrt-iter itself, using new-if would invoke an infinite loop.
In the sample (sqrt x) procedure in this chapter, a good-enough procedure is used to judge whether the approximation of the sqrt is accurate enough:
(define (good-enough? guess x) (< (abs (- (square guess) x)) 0.001))We say that the guess is good enough if the difference between guess square and x is fewer than a value, 0.001 here. However, this method has its limitation. When x is very big or very small, the fixed value of 0.001 cannot play its role effectively. (you can try!) So I write a new procedure for this exercise:
(define (average x y) (/ (+ x y) 2.0)) (define (square x) (* x x)) (define (sqrt x) (define (good-enough? guess old-guess) (< (abs (/ (- guess old-guess) old-guess)) 0.00000001)) (define (improve guess) (average guess (/ x guess))) (define (sqrt-iter guess old-guess) (if (good-enough? guess old-guess) guess (sqrt-iter (improve guess) guess))) (sqrt-iter 1.0 -1.0))Notice that I have put procedures like good-enough? and improve into the definition of sqrt. Doing so can reduce confusion (as good-enough? and guess are common names but should only be useful in the sqrt procedure) and reduce the number of parameters in each procedure (x needs not to be passed due to its lexical scope).
This one is similar to 1.7 but this time I am solving for the cube root.
(define (pow x y) (if (= y 0) 1 (* x (pow x (- y 1))))) (define (cube-root x) (define (good-enough? guess old-guess) (< (abs (/ (- guess old-guess) old-guess)) 0.00000001)) (define (improve guess) (/ (+ (/ x (pow guess 2)) (* 2 guess)) 3)) (define (cube-root-iter guess old-guess) (if (good-enough? guess old-guess) guess (cube-root-iter (improve guess) guess))) (cube-root-iter 1.0 -1.0)) (cube-root -8)I have added a test case -8 to show that this procedure can handle the negative root as well.
Do you find coding in Scheme interesting? Or are you interested in the Wizard Book? Join me to read the book so that we can share our thoughts!
[SICP Notes] 1.1 The Elements of Programming,布布扣,bubuko.com
[SICP Notes] 1.1 The Elements of Programming
标签:scheme recursion lisp sicp procedure
原文地址:http://blog.csdn.net/redcapcoder/article/details/38133753