Recursion and Iteration
Let the entertainment begin…
CS 480/680
–
Comparative Languages
Recursion and Iteration
2
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 Cal
-
Tech:
Recursion and Iteration
3
Summing integers
How do I compute the sum of the first N
integers?
Recursion and Iteration
4
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
5
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
6
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
7
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
8
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
9
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
10
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
11
Evaluating…
Evaluate:
(if (= 3 0) 0 (+ 3 (sum
-
integers (
-
3 1))))
•
evaluate
(= 3 0)
evaluate
3
3
evaluate
0
0
evaluate
=
=
apply
=
to
3
,
0
#f
•
since expression is false,
replace with false clause:
(+ 3 (sum
-
integers (
-
3 1)))
•
evaluate:
(+ 3 (sum
-
integers (
-
3 1)))
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 …))
Recursion and Iteration
13
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
14
Evaluating…
apply
(lambda (n)
(if (= n 0)
0
(+ n (sum
-
integers (
-
n 1)))))
to
2
(if (= 2 0) 0 (+ 2 (sum
-
integers (
-
2 1)))
Pending (+ 3 …)
Recursion and Iteration
15
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)))
Pending (+ 3 …)
Recursion and Iteration
16
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
Pending (+ 3 …)
Note: pending (+ 3 (+ 2 …))
Recursion and Iteration
17
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
Pending (+ 3 (+ 2 …))
Note: pending (+ 3 (+ 2 (+ 1 0)))
Recursion and Iteration
18
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
Pending (+ 3 (+ 2 (+ 1 0)))
Note: pending (+ 3 (+ 2
1
))
Recursion and Iteration
19
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
Pending (+ 3 (+ 2 1))
Note: pending (+ 3
3
)
Recursion and Iteration
20
Evaluating
Finish pending:
(+ 3 3)
… final result:
6
Recursion and Iteration
21
…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
22
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
23
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
24
List Processing
Suppose I want to search a list for the max
value?
A standard list:
What is the base case?
What state do I need to maintain?
3
7
4
1
lst
Recursion and Iteration
25
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?
3
7
4
1
lst
5
2
3
9
Recursion and Iteration
26
Using Recursion
Write avg.scheme
See list
-
position.scheme
See count_atoms.scheme
See printtype.scheme
Recursion and Iteration
27
Mutual Recursion
Note: Scheme has built
-
in primitives
even?
and
odd?
(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)))))
Recursion and Iteration
28
Recursion and Local Definitions
Recursion gets more difficult when you want
the functions to be local in scope:
(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)))
local
-
odd? is not yet defined
Can we fix this with let* ?
Recursion and Iteration
29
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
30
Recursion for loops
Instead of a for loop, this letrec uses a recursive
procedure on the variable
i
, which starts at 10 in
the procedure call.
(letrec ((countdown (lambda (i)
(if (= i 0) 'liftoff
(begin
(display i)
(newline)
(countdown (
-
i 1)))))))
(countdown 10))
Recursion and Iteration
31
Named
let
This is the same as the previous definition, but
written more compactly
Named
let
is useful for
defining and running
loops
((let countdown ((i 10))
(if (= i 0) 'liftoff
(begin
(display i)
(newline)
(countdown (
-
i 1)))))
Recursion and Iteration
32
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
33
Stack Frames
Each call to Fib
produces a new
stack frame
1000 recursive calls
= 1000 stack frames!
Inefficient
relative to
a
for
loop
N
prev
pprev
N
prev
pprev
Recursion and Iteration
34
How can we fix this inefficiency?
Here’s an answer from the Cal
-
Tech slides:
Recursion and Iteration
35
Example
Recall from last time:
(define (sum
-
integers n)
(if (= n 0)
0
(+ n (sum
-
integers (
-
n 1)))))
Recursion and Iteration
36
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
37
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
38
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
39
What can we say about the
computation?
On input
N
:
How many calls to
sum
-
integers
?
N+1
How much work per call?
(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
40
Linear recursive processes
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
(sum
-
integers 3)
(+ 3 (sum
-
integers 2))
(+ 3 (+ 2 (sum
-
integers 1)))
(+ 3 (+ 2 (+ 1 (sum
-
integers 0))))
(+ 3 (+ 2 (+ 1 0)))
time = C
1
+ N*C
2
Recursion and Iteration
41
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
42
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
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))))
(sum
-
int 3)
(sum
-
iter 0 3
0
)
Recursion and Iteration
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))))
(sum
-
int 3)
(sum
-
iter
0
3
0
)
(if (> 0 3) … )
(sum
-
iter 1 3
0
)
Recursion and Iteration
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))))
(sum
-
int 3)
(sum
-
iter 0 3 0)
(if (> 0 3) … )
(sum
-
iter
1
3
0
)
(if (> 1 3) … )
(sum
-
iter 2 3
1
)
Recursion and Iteration
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))))
(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
)
Recursion and Iteration
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))))
(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
)
Recursion and Iteration
48
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))))
(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
Recursion and Iteration
49
What can we say about the
computation?
on input
N
:
How many calls to
sum
-
iter
?
N+2
How much work per call?
(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
50
What can we say about the
computation?
on input
N
:
How many calls to
sum
-
iter
?
N+2
How much work per call?
constant
one comparison, one if,
two additions, one call
How many deferred
operations?
none
(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
51
What’s different about these
computations?
(sum
-
integers 3)
(+ 3 (sum
-
integers 2))
(+ 3 (+ 2 (sum
-
integers 1)))
(+ 3 (+ 2 (+ 1 (sum
-
integers 0))))
(+ 3 (+ 2 (+ 1 0)))
(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)
Old
Ne
w
Recursion and Iteration
52
Linear iterative processes
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
•
(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 = C
1
+ N*C
2
Recursion and Iteration
53
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
54
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
55
Tail
-
call elimination
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
((let countdown ((i 10))
(if (= i 0) 'liftoff
(begin
(display i)
(newline)
(countdown (
-
i 1)))))
Recursion and Iteration
56
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
57
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)
Enter the password to open this PDF file:
File name:
-
File size:
-
Title:
-
Author:
-
Subject:
-
Keywords:
-
Creation Date:
-
Modification Date:
-
Creator:
-
PDF Producer:
-
PDF Version:
-
Page Count:
-
Preparing document for printing…
0%
Comments 0
Log in to post a comment