Title: Recursion
1Recursion
2Definitions I
- A recursive definition is a definition in which
the thing being defined occurs as part of its own
definition - Example A list consists of
- An open parenthesis, "("
- Zero or more atoms or lists, and
- A close parenthesis, ")"
3Definitions II
- Indirect recursion is when a thing is defined in
terms of other things, but those other things are
defined in terms of the first thing - Example A list is
- An open parenthesis,
- Zero or more S-expressions, and
- A close parenthesis
- An S-expression is an atom or a list
4Understanding recursion
- The usual way to teach recursion is to trace
through a recursion, seeing what it does at each
level - This may be a good way to understand how
recursion works... - ...but it's a terrible way to try to use
recursion - There is a better way
5Base cases and recursive cases
- Every valid recursive definition consists of two
parts - One or more base cases, where you compute the
answer directly, without recursion - One or more recursive cases, where you do part of
the work, and recur with a simpler problem
6Information hiding
- function spread (int A, int size) int
max, min sort(A, size) min A0
max Asize - 1 return max - min - Can you understand this function without looking
at sort?
7Stepping through called functions
- Functions should do something simple and
understandable - When you try to understand a function, you should
not have to step through the code of the
functions that it calls - When you try to understand a recursive function,
you should not have to step through the code of
the functions it calls
8We have small heads
- It's hard enough to understand one level of one
function at a time - It's almost impossible to keep track of many
levels of the same function all at once - But you can understand one level of one function
at a time... - ...and that's all you need to understand in order
to use recursion well
9The four rules
- Do the base cases first
- Recur only with a simpler case
- Don't use global or reference variables
- Don't look down
10Do the base cases first
- Every recursive function must have some things it
can do without recursion - These are the simple, or base, cases
- Test for these cases, and do them first
- This is just writing ordinary, nonrecursive code
11Recur only with a simpler case
- If the problem isn't simple enough to be a base
case, break it into two parts - A simpler problem of the same kind (for example,
a smaller number, or a shorter list) - Extra work not solved by the simpler problem
- Combine the results of the recursion and the
extra work into a complete solution - Simpler means more like a base case
12Example 1 member
- Is value X a member of list L ?
- boolean member(X, L)
- if (L is the empty list) return
false // this is a base case - if (X equals the first element in L)
return true // another base case - return member(X, L - first element)
// simpler because more like empty list
13MEMBER in Lisp
(DEFUN MEMBER (X L) (COND base case L is
empty ((NULL L) NIL) base case X (CAR
L) ((EQ X (CAR L)) T) recur with a case
that is simpler because its more like 1st
base case (T (MEMBER X (CDR L))) ) )
14Example 2 double
- Double every element of a list of numbers
- function double(L)
- if (L is the empty list) return the
empty list // base case - else L2 double (L - first
element) // recur - D 2 first element in L
// extra work - return (list made by adding D to L2) //
combine
15DOUBLE in Lisp
(DEFUN DOUBLE (L) (COND if L is the empty
list, return the empty list ((NULL L) ())
otherwise, double the first number and cons it
to the double of the rest of the list (T (CONS
( 2 (CAR L)) (DOUBLE (CDR L))) ) )
16It's OK to use locals variables and parameters
passed by value
- A function has its own copy of
- local variables
- parameters passed by value
- Each level of a recursive function has its own
copy of these variables and parameters - Changing them at one level does not change them
at other levels - One level can't interfere with another level
17It's bad to use global variables or parameters
passed by reference
- There is only one copy of a global variable
- If a parameter is passed by reference, there is
only one copy of it - If such a variable is changed by a recursive
function, it's changed at all levels - The various levels interfere with one another
- This can get very confusing
- Don't let this happen to you!
18Don't look down
- When you write or debug a recursive function,
think about this level only - Wherever there is a recursive call, assume that
it works correctly - If you can get this level correct, you will
automatically get all levels correct - You really can't understand more than one level
at a time, so don't even try
19MEMBER again
- (DEFUN MEMBER (X L) (COND ((NULL L) NIL)
- This says if list L is empty, then X isnt an
element of L - Is this a true statement?
- ((EQ X (CAR L)) T)
- This says if X the first element in L, then
its in L - Is this a true statement?
- (T (MEMBER X (CDR L))) ) )
- This says if X isnt the first element of L,
then X is in L if and only if X is in the tail of
L - Is this a true statement?
- Did we cover all possible cases?
- Did we recur only with simpler cases?
- Did we change any global variables?
- Were done!
20Reprise
- Do the base cases first
- Recur only with a simpler case
- Don't use global or reference variables
- Don't look down
21The End