# CS790 – Introduction to Bioinformatics

Biotechnology

Oct 2, 2013 (4 years and 7 months ago)

104 views

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,

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

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

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

»

(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)