Recursion and Iteration

advertisement
CS 480/680 – Comparative Languages
Recursion and Iteration
Let the entertainment begin…
No Iteration??
 Yes, it’s true, there is no iteration in Scheme.
So, how do we achieve simple looping
constructs? Here’s a simple example from CalTech:
Recursion and Iteration
2
Summing integers
 How do I compute the sum of the first N
integers?
Recursion and Iteration
3
Decomposing the sum
 Sum of first N integers =
 N + N-1 + N-2 + … 1
 N + ( N-1 + N-2 + … 1 )
 N + [sum of first N-1 integers]
Recursion and Iteration
4
to Scheme
 Sum of first N integers =
N + [sum of first N-1 integers]
 Convert to Scheme (first attempt):
(define (sum-integers n)
(+ n (sum-integers (- n 1))))
Recursion and Iteration
5
Recursion in Scheme
 (define (sum-integers n)
(+ n (sum-integers (- n 1))))
 sum-integers defined in terms of itself
 This is a recursively defined procedure
... which is incorrect
 Can you spot the error?
Recursion and Iteration
6
Almost…
 What’s wrong?
(define (sum-integers n)
(+ n (sum-integers (- n 1))))
 Gives us:
N + N-1 + …+ 1 + 0 + -1 + -2 + …
Recursion and Iteration
7
Debugging
 Fixing the problem:
• it doesn’t stop at zero!
 Revised:
(define (sum-integers n)
(if (= n 0)
0
(+ n (sum-integers (- n 1)))))
 How does this evaluate?
Recursion and Iteration
8
Warning
 The substitution evaluation you are about to
see is methodical, mechanistic,
• and extremely tedious.
 It will not all fit on one slide.
 Don't take notes, but instead try to grasp the
overall theme of the evaluation.
Recursion and Iteration
9
Evaluating
 Evaluate: (sum-integers 3)
• evaluate 3  3
• evaluate sum-integers  (lambda (n) (if …))
• apply (lambda (n)
(if (= n 0)
0
(+ n (sum-integers (- n 1))))) to 3
 (if (= 3 0) 0 (+ 3 (sum-integers (- 3 1))))
Recursion and Iteration
10
Evaluating…
 Evaluate: (if (= 3 0) 0 (+ 3 (sum-integers (- 3 1))))
• evaluate (= 3 0)



evaluate 3  3
evaluate 0  0
evaluate =  =
= to 3, 0  #f
• since expression is false,
 replace with false clause:
 apply
(+ 3 (sum-integers (- 3 1)))
• evaluate: (+ 3 (sum-integers (- 3 1)))
Recursion and Iteration
11
Evaluating…
 evaluate (+ 3 (sum-integers (- 3 1)))
• evaluate 3  3
• evaluate (sum-integers (- 3 1))
 evaluate (- 3 1) ...[skip steps] …  2
 evaluate sum-integers(lambda (n) (if …))
Recursion and Iteration
12
Evaluating…
 evaluate (+ 3 (sum-integers (- 3 1)))
• evaluate 3  3
• evaluate (sum-integers (- 3 1))
 evaluate (- 3 1) ...[skip steps] …  2
 evaluate sum-integers(lambda (n) (if …))
Note: now pending (+ 3 …)
Recursion and Iteration
13
Pending (+ 3 …)
Evaluating…
 apply (lambda (n)
(if (= n 0)
0
(+ n (sum-integers (- n 1))))) to 2
 (if (= 2 0) 0 (+ 2 (sum-integers (- 2 1)))
Recursion and Iteration
14
Pending (+ 3 …)
Evaluating…
 evaluate: (if (= 2 0) 0 (+ 2 (sum-integers (- 2 1)))
• evaluate (= 2 0) … [skip steps] …  #f
• since expression is false,
 replace with false clause
• (+ 2 (sum-integers (- 2 1)))
• evaluate: (+ 2 (sum-integers (- 2 1)))
Recursion and Iteration
15
Pending (+ 3 …)
Evaluating…
 evaluate (+ 2 (sum-integers (- 2 1)))
• evaluate 2  2
• evaluate (sum-integers (- 2 1))
 evaluate (- 2 1) ...[skip steps] …  1
 evaluate sum-integers(lambda (n) (if …))
 apply (lambda (n) …) to 1
 (if (= 1 0) 0 (+ 1 (sum-integers (- 1 1))))
– evaluate (= 1 0) ...[skip steps] …  #f
Recursion and Iteration
Note: pending (+ 3 (+ 2 …))
16
Pending (+ 3 (+ 2 …))
Evaluating…
 Evaluate (+ 1 (sum-integers (- 1 1)))
• evaluate 1  1
• evaluate (sum-integers (- 1 1))
 evaluate (- 1 1) ...[skip steps] …  0
 evaluate sum-integers(lambda (n) (if …))
 apply (lambda (n) …) to 0
 (if (= 0 0) 0 (+ 1 (sum-integers (- 0 1))))
– evaluate (= 0 0)  #t
– result: 0
Recursion and Iteration
17
Note: pending (+ 3 (+ 2 (+ 1 0)))
Pending (+ 3 (+ 2 (+ 1 0)))
Evaluating
Back to pending:
 Know (sum-integers (- 1 1))  0 [prev slide]
 Evaluate (+ 1 (sum-integers (- 1 1)))
•
•
•
•
evaluate 1  1
evaluate (sum-integers (- 1 1))  0
evaluate +  +
apply + to 1, 0  1
Note: pending (+ 3 (+ 2 1))
Recursion and Iteration
18
Pending (+ 3 (+ 2 1))
Evaluating
Back to pending:
 Know (sum-integers (- 2 1))  1 [prev slide]
 Evaluate (+ 2 (sum-integers (- 2 1)))
•
•
•
•
evaluate 2  2
evaluate (sum-integer (- 2 1))  1
evaluate +  +
apply + to 2, 1  3
Note: pending (+ 3 3)
Recursion and Iteration
19
Evaluating
Finish pending:
 (+ 3 3)
 … final result: 6
Recursion and Iteration
20
…Yeah!!! …
Substitution model…
 …works fine for recursion.
 Recursive calls are well-defined.
 Careful application of model shows us what
they mean and how they work.
Recursion and Iteration
21
Recursive Functions
 Since there are no iterative constructs in
Scheme, most of the power comes from writing
recursive functions
 This is fairly straightforward if you want the
procedure to be global:
(define factorial
(lambda (n)
(if (= n 0) 1
(* n (factorial (- n 1))))))
(factorial 5) » 120
Recursion and Iteration
22
The trick
 Must find the structure of the problem:
• How can I break it down into sub-problems?
• What are the base cases?
Recursion and Iteration
23
List Processing
 Suppose I want to search a list for the max
value?
 A standard list:
lst
3
7
4
1
 What is the base case?
 What state do I need to maintain?
Recursion and Iteration
24
More list processing
 How about a list of X-Y pairs?
• What would the list look like?
 Given X, find Y:
• Base case
• State
• Helper procedures?
lst
3
Recursion and Iteration
5
7
2
4
3
1
9
25
Using Recursion




Write avg.scheme
See list-position.scheme
See count_atoms.scheme
See printtype.scheme
Recursion and Iteration
26
Mutual Recursion
(define is-even?
(lambda (n)
(if (= n 0) #t
(is-odd? (- n 1)))))
(define is-odd?
(lambda (n)
(if (= n 0) #f
(is-even? (- n 1)))))
 Note: Scheme has built-in primitives even?
and odd?
Recursion and Iteration
27
Recursion and Local Definitions
 Recursion gets more difficult when you want
the functions to be local in scope:
local-odd? is not yet defined
(let ((local-even? (lambda (n)
(if (= n 0) #t
(local-odd? (- n 1)))))
(local-odd? (lambda (n)
(if (= n 0) #f
(local-even? (- n 1))))))
(list (local-even? 23) (local-odd? 23)))
Can we fix this with let* ?
Recursion and Iteration
28
letrec
 letrec – the variables introduced by letrec are
available in both the body and the initializations
• Custom made for local recursive definitions
(letrec ((local-even? (lambda (n)
(if (= n 0) #t
(local-odd? (- n 1)))))
(local-odd? (lambda (n)
(if (= n 0) #f
(local-even? (- n 1))))))
(list (local-even? 23) (local-odd? 23)))
Recursion and Iteration
29
Recursion for loops
(letrec ((countdown (lambda (i)
(if (= i 0) 'liftoff
(begin
(display i)
(newline)
(countdown (- i 1)))))))
(countdown 10))
 Instead of a for loop, this letrec uses a recursive
procedure on the variable i, which starts at 10 in
the procedure call.
Recursion and Iteration
30
Named let
((let countdown ((i 10))
(if (= i 0) 'liftoff
(begin
(display i)
(newline)
(countdown (- i 1)))))
 This is the same as the previous definition, but
written more compactly
 Named let is useful for defining and running
loops
Recursion and Iteration
31
Recursion and Stack Frames
 What happens when we
call a recursive function?
 Consider the following
Fibonacci function:
int fib(int N) {
int prev, pprev;
if (N == 1) {
return 0;
}
else if (N == 2) {
return 1;
}
else {
prev = fib(N-1);
pprev = fib(N-2);
return prev + pprev;
}
}
Recursion and Iteration
32
Stack Frames
 Each call to Fib
produces a new
stack frame
 1000 recursive calls
= 1000 stack frames!
 Inefficient relative to
a for loop
Recursion and Iteration
pprev
prev
N
pprev
prev
N
33
 How can we fix this inefficiency?
 Here’s an answer from the Cal-Tech slides:
Recursion and Iteration
34
Example
 Recall from last time:
(define (sum-integers n)
(if (= n 0)
0
(+ n (sum-integers (- n 1)))))
Recursion and Iteration
35
Revisited (summarizing steps)








Evaluate: (sum-integers 3)
(if (= 3 0) 0 (+ 3 (sum-integers (- 3 1))))
(if #f
0 (+ 3 (sum-integers (- 3 1))))
(+ 3 (sum-integers (- 3 1)))
(+ 3 (sum-integers 2))
(+ 3 (if (= 2 0) 0 (+ 2 (sum-integers (- 2 1)))))
(+ 3 (+ 2 (sum-integers 1)))
(+ 3 (+ 2 (if (= 1 0) 0 (+ 1 (sum-integer (- 1 1))))))
Recursion and Iteration
36
Revisited (summarizing steps)






(+ 3 (+ 2 (+ 1 (sum-integers 0))))
(+ 3 (+ 2 (+ 1 (if (= 0 0) 0 …))))
(+ 3 (+ 2 (+ 1 (if #t
0 …))))
(+ 3 (+ 2 ( + 1 0)))
…
6
Recursion and Iteration
37
Evolution of computation





(sum-integers 3)
(+ 3 (sum-integers 2))
(+ 3 (+ 2 (sum-integers 1)))
(+ 3 (+ 2 (+ 1 (sum-integers 0))))
(+ 3 (+ 2 (+ 1 0)))
Recursion and Iteration
38
What can we say about the
computation?
(sum-integers 3)
(+ 3 (sum-integers 2))
(+ 3 (+ 2 (sum-integers 1)))
(+ 3 (+ 2 (+ 1 (sum-integers 0))))
(+ 3 (+ 2 (+ 1 0)))
Recursion and Iteration
On input N:
 How many calls to sumintegers?
N+1
 How much work per call?
39
Linear recursive processes
(sum-integers 3)
(+ 3 (sum-integers 2))
(+ 3 (+ 2 (sum-integers 1)))
(+ 3 (+ 2 (+ 1 (sum-integers 0))))
(+ 3 (+ 2 (+ 1 0)))
 time = C1 + N*C2
Recursion and Iteration
 This is what we call a
linear recursive process
 Makes linear # of calls
• i.e. proportional to N
 Keeps a chain of deferred
operations linear in size
w.r.t. input
• i.e. proportional to N
40
Another strategy
To sum integers…
add up as we go along:
 1 2 3 4 5 6 7…
 1 1+2 1+2+3 1+2+3+4 ...
 1 3 6 10 15 21 28 …
Recursion and Iteration
41
Alternate definition
(define (sum-int n)
(sum-iter 0 n 0)) ;; start at 0, sum is 0
(define (sum-iter current max sum)
(if (> current max)
sum
(sum-iter (+ 1 current)
max
(+ current sum))))
Recursion and Iteration
42
Evaluation of sum-int
(define (sum-int n)
(sum-iter 0 n 0))
(define (sum-iter current
max
sum)
(if (> current max) sum
(sum-iter (+ 1 current)
max
(+ current
sum))))
Recursion and Iteration
 (sum-int 3)
 (sum-iter 0 3 0)
43
Evaluation of sum-int
(define (sum-int n)
(sum-iter 0 n 0))
(define (sum-iter current
max
sum)
(if (> current max) sum
(sum-iter (+ 1 current)
max
(+ current
sum))))
Recursion and Iteration




(sum-int 3)
(sum-iter 0 3 0)
(if (> 0 3) … )
(sum-iter 1 3 0)
44
Evaluation of sum-int
(define (sum-int n)
(sum-iter 0 n 0))
(define (sum-iter current
max
sum)
(if (> current max) sum
(sum-iter (+ 1 current)
max
(+ current
sum))))
Recursion and Iteration






(sum-int 3)
(sum-iter 0 3 0)
(if (> 0 3) … )
(sum-iter 1 3 0)
(if (> 1 3) … )
(sum-iter 2 3 1)
45
Evaluation of sum-int
(define (sum-int n)
(sum-iter 0 n 0))
(define (sum-iter current
max
sum)
(if (> current max) sum
(sum-iter (+ 1 current)
max
(+ current
sum))))
Recursion and Iteration








(sum-int 3)
(sum-iter 0 3 0)
(if (> 0 3) … )
(sum-iter 1 3 0)
(if (> 1 3) … )
(sum-iter 2 3 1)
(if (> 2 3) … )
(sum-iter 3 3 3)
46
Evaluation of sum-int
(define (sum-int n)
(sum-iter 0 n 0))
(define (sum-iter current
max
sum)
(if (> current max) sum
(sum-iter (+ 1 current)
max
(+ current
sum))))
Recursion and Iteration










(sum-int 3)
(sum-iter 0 3 0)
(if (> 0 3) … )
(sum-iter 1 3 0)
(if (> 1 3) … )
(sum-iter 2 3 1)
(if (> 2 3) … )
(sum-iter 3 3 3)
(if (> 3 3) … )
(sum-iter 4 3 6)
47
Evaluation of sum-int
(define (sum-int n)
(sum-iter 0 n 0))
(define (sum-iter current
max
sum)
(if (> current max) sum
(sum-iter (+ 1 current)
max
(+ current
sum))))
Recursion and Iteration












(sum-int 3)
(sum-iter 0 3 0)
(if (> 0 3) … )
(sum-iter 1 3 0)
(if (> 1 3) … )
(sum-iter 2 3 1)
(if (> 2 3) … )
(sum-iter 3 3 3)
(if (> 3 3) … )
(sum-iter 4 3 6)
(if (> 4 3) … )
6
48
What can we say about the
computation?







(sum-int 3)
(sum-iter 0 3 0)
(sum-iter 1 3 0)
(sum-iter 2 3 1)
(sum-iter 3 3 3)
(sum-iter 4 3 6)
6
Recursion and Iteration
on input N:
 How many calls to sumiter?
N+2
 How much work per call?
49
What can we say about the
computation?







(sum-int 3)
(sum-iter 0 3 0)
(sum-iter 1 3 0)
(sum-iter 2 3 1)
(sum-iter 3 3 3)
(sum-iter 4 3 6)
6
on input N:
 How many calls to sumiter?
N+2
 How much work per call?
constant

one comparison, one if,
two additions, one call
 How many deferred
operations?
none
Recursion and Iteration
50
What’s different about these
computations?
Old
(sum-integers 3)
(+ 3 (sum-integers 2))
(+ 3 (+ 2 (sum-integers 1)))
(+ 3 (+ 2 (+ 1 (sum-integers 0))))
(+ 3 (+ 2 (+ 1 0)))
Recursion and Iteration
New
(sum-int 3)
(sum-iter 0 3 0)
(sum-iter 1 3 0)
(sum-iter 2 3 1)
(sum-iter 3 3 3)
(sum-iter 4 3 6)
51
Linear iterative processes
•
•
•
•
•
•
•
(sum-int 3)
(sum-iter 0 3 0)
(sum-iter 1 3 0)
(sum-iter 2 3 1)
(sum-iter 3 3 3)
(sum-iter 4 3 6)
6
 time = C1 + N*C2
Recursion and Iteration
 This is what we call a
linear iterative process
 Makes linear # calls
 State of computation kept
in a constant # of
state variables
• state does not grow with
problem size
• requires a constant amount
of storage space
52
Linear recursive vs linear iterative
 Both require computational time which is
linear in size of input
 L.R. process requires space that is also
linear in size of input
• why?
 L.I. process requires constant space
• not proportional to size of input
• more space-efficient than L.R. process
Recursion and Iteration
53
Linear recursive vs linear iterative
 Why not always use linear iterative
instead of linear recursive algorithm?
• often the case in practice
 Recursive algorithm sometimes much
easier to write
• and to prove correct
 Sometimes space efficiency not the
limiting factor
Recursion and Iteration
54
Tail-call elimination
((let countdown ((i 10))
(if (= i 0) 'liftoff
(begin
(display i)
(newline)
(countdown (- i 1)))))
 Countdown uses only tail-recursion
• Each call to countdown either does not call itself
again, or does it as the very last thing done
 Scheme recognizes tail recursion and converts
it to an iterative (loop) construct internally
Recursion and Iteration
55
Mapping a procedure across a list
(map add2 '(1 2 3))
» (3 4 5)
(map cons '(1 2 3) '(10 20 30))
» ((1 . 10) (2 . 20) (3 . 30))
(map + '(1 2 3) '(10 20 30))
» (11 22 33)
Recursion and Iteration
56
Exercises
 Include error checking into avg.scheme
• Divide by zero error
• Non-numeric list items
 Write a scheme function that accepts a single
numeric argument and returns all numbers less
than 10 that the argument is divisible by
 Factor.scheme – described in class
 Write a scheme function that returns the first n
Fibonacci numbers as a list (n is an argument)
Recursion and Iteration
57
Download