95.501 | 2000 |
3 Building Abstractions with Procedures |
3.1 Conditional Expressions and Predicates |
|x| = x if x>0
0 of x = 0
-x if x <= 0
(cond ( <p1> <e1>)
( <p2> <e2>)
...
( <pn> <en>))
(define (abs x)
(cond (( > x 0) x)
(( = x 0) 0)
((< x 0) (- x))))
(define (abs x)
(cond (( < x 0) (- x))
(else x)))
(define (abs x)
(if (< x 0)
(- x)
x))
(if <predicate> <consequent> <alternative> )
(and <e1> ... <en>) evaluate left to right, as soon as one expression is false return false(or <e1> ... <en>) evaluate left to right, as soon as one expression is true return true
(not <e>)
(define (>= x y)
(or ( > x y) (= x y))(define (>= x y)
(not (< x y))
Guess (y) | Quotient (x/y) | Average ((x/y) + y) / 2 => gives next guess |
1 | 2/1 = 2 | (2 + 1)/2 = 1.5 |
1.5 | 2/1.5= 1.333 | (1.3333 + 1.5) / 2 = 1.4167 |
1.4167 | 2/1.4167= 1.4118 | (1.4167 + 1.4118) / 2 = 1.4142 |
1.4142 | ... | ... |
(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-iteration guess x)
(if (good-enough? guess x)
guess
(sqrt-iteration (improve guess x) x)))(define (sqrt x)
(sqrt-iteration 1.0 x))
Sqrt is first example of process defined by a set of mutually defined procedures Problem breaks up naturally into subproblems: decomposition strategy Details of how sqrt is computed can be hidden (black box) creating a so-called procedural abstraction Take the procedure square, we know what we want, but how does it do it?
(define (square x) ( * x x))(define (square x) (exp (double (log x))))
(define (double x) ( + x x ))
A procedure definition should be able to supress details Users of procedure may not have written it Users should not need to know how a procedure is implemented in order to use it!
(define (sqrt x)
(define (good-enough guess)
(< (abs (- (square guess) x)) 0.001))
(define (improve guess)
(average guess ( / x guess)))
(define (sqrt-iteration guess)
(if (good-enough? guess x)
guess
(sqrt-iteration (improve guess x) x)))
(sqrt-iteration 1.0))
Users view of sqrt procedure
(define (sqrt x) ....)
User cannot directly use procedures good-enough, improve
and sqrt-iteration
3.2 Procedures and the Processes They Generated |
n! = n * (n - 1) * (n - 2) . . . 3 * 2 * 1
n! = n * (n - 1)!
(define (factorial n)
(if ( = n 1)
1
(* n (factorial ( - n 1)))))Substitution Model for (factorial 5)
(factorial 5)
(* 5 (factorial 4))
(* 5 (* 4 (factorial 3)))
(* 5 (* 4 (* 3 (factorial 2))))
(* 5 (* 4 (* 3 (* 2 (factorial 1)))))
(* 5 (* 4 (* 3 (* 2 1))))
(* 5 (* 4 (* 3 2)))
(* 5 (* 4 6))
(* 5 24)
120This is a linear recursive process
- expansion followed by contraction
- chain of deferred operations (*)
- interpreter keeps track of operations to perform later
- amount of information to keep track of grows linearly
(define (factorial n)
(factorial-iteration 1 1 n))(define (factorial-iteration product counter maximum)
(if (> counter maximum)
product
(factorial-iteration (* counter product) (+ counter 1) maximum)))Substitution Model for (factorial 5)
(factorial 5)
(factorial-iteration 1 1 5)
(factorial-iteration 1 2 5)
(factorial-iteration 2 3 5)
(factorial-iteration 6 4 5)
(factorial-iteration 24 5 5)
(factorial-iteration 120 6 5)
120This is a linear iterative process
- state can be summarized by a fixed number of state variables together with a rule on how to update them
- end test is optional
- number of steps grows linearly
3.3 Other Forms of Recursion |
Fibonacci NumbersFib(n) = 0 if n = 0
Fib(n) = 1 if n = 1
Fib(n) = Fib(n - 1) + Fib(n - 2) otherwise0, 1, 1, 2, 3, 5, 8, 13, 21 ....
(define (fib n)
(cond (( = n 0) 0)
(( = n 1) 1)
(else
(+ (fib (- n 1))
(fib ( - n 2))))))
![]()
process looks like a tree inefficient due to duplicate computation
(define (fib n)
(fib-iteration 1 0 n))(define (fib-iteration a b count)
(if (= count 0)
b
(fib-iteration ( + a b) a (- count 1))))(fib 4)
(fib-iteration 1 0 4)
(fib-iteration 1 1 3)
(fib-iteration 2 1 2)
(fib-iteration 3 2 3)
(fib-iteration 5 3 0)
3
3.4 Procedures |
(define (sum-int a b)
(if (> a b)
0
(+ a
(sum-int (+ a 1) b))))
(define (cube x) (* x x x ))(define (sum-cubes a b)
(if ( > a b)
0
(+ (cube a)
(sum-cubes (+ a 1) b))))
Compute (1/(1 * 3)) + (1/(5 * 7)) + (1/(9 * 11)) + . . . converges to pi/8
(define (pi-sum a b)
(if ( > a b)
0
(+ (/ 1.0 (* a (+ a 2))
(pi-sum (+ a 4) b))))
(define (sum term a next b)
(if ( > a b)
0
(+ (term a)
(name (next a) b ))))
(define (inc n) (+ n 1))
(define (identity n) n)(define (sum-int a b)
(sum identity a inc b))(define (sum-cubes a b)
(sum cube a inc b))(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))
(lambda (<formal parameters>) <body>)
(lambda (x) (+ x 4)) returns a procedure that increments x by 4 like pi-next
(lambda (x) (/ 1.0 (* x (+ x 2)))) returns a procedure that is like pi-term
(define (plus4 x) (+ x 4)) is equivalent to (define plus4 (lambda (x) (+ x 4)))
Note: Evaluating a lambda expression returns a procedure object
Therefore:
((lambda (x) (+ 1 x)) 2) => 3in the same way:(define (increment x)or
(+ 1 x))
(increment 2) => 3(define increment (lambda (x) (+ 1 x)))
(increment 2) => 3
f(x,y) = x(1 + xy)(1 + xy) + y(1 -y) + (1 + xy)(1 -y)Let's write the function f in schemeif a = 1 + xy and b= 1-y
f(x,y) = xaa + yb + ab
(define (f x y)We could use lambda instead creating two variables a b that get bound to (+ 1 (* x y)) and (- 1 y)) respectively
(define (f-helper a b)
(+ (* x (square a))
(* y b)
(* a b)))
(f-helper (+ 1 (* x y))
(- 1 y)))
(define (f x y)
((lambda a b)
(+ (* x (square a))
(* y b)
(* a b)))
(+ 1 (* x y))
(- 1 y)))
The syntax for lambda
((lambda (<var1> ...<varn>)can be expressed using the special form let
<body>)
<exp1>
<exp2>
.
.
.
<expn>)
(let ((<var1> <exp1>)which can be thought of as
(<var2> <exp2>)
.
.
.
(<varn> <expn>))
<body>)
let <var1> have the value <exp1> andTherefore
<var2> have the value <exp2> and
.
.
.
<varn> have the value <expn> and
in <body>
(let ((x 3)
(y (+ x 3)))
(* x y))=> with generate the value 12 when evaluated
Note: Scope of variables is in let expression
Therefore:
(define x 5)Back to our Example
(+ (let (( x 3))
(+ x (* x 10)))
x)=> 38
(define (f x y)
(let (( a (+ 1 (* x y)))
( b (- 1 y)))
(+
(* x (square x))
( * y b)
(* a b))))
(f square) =>? 4 is the answer
(f (lambda (z) (* z (+ z 1)))) =>? 6 is the answer
(f f) => ? we will get an error by attempting to evaluate 2 as a procedure, the trace is as follows
(f f)
(f 2)
(2 2)
(define (average-damp f)
(lambda (x) (average x (f x))))
Applying average-damp to the square procedure returns a procedure whose value when evaluated is the average of x and x squared
((average-damp square) 10) => 55
3.5 Summary |