Recursion

So far, all the programs we can write will run very quickly! Roughly speaking, the number of steps they take can't be larger than the size of the program.

To obtain the computing power of ordinary languages, or Turing machines, etc., we need a way to repeat computations.

Most languages support loops. SML does have a loop construct:

but this is completely useless in pure programs. (Why?)

Pure functional programs use recursive functions instead of iteration to achieve repetition. Crucial difference is that each recursive activation of a function provides new actual parameters to be bound to the function's formal parameters.

So, the function can compute something different each time it is called!

Recursion is not hard

Recursive definition is one that mentions the thing being defined in the body of the definition.

Define ``ancestor.''

Factorial.

Insertion sort.

Quick sort.

Towers of Hanoi.

Key idea: Recursive calls must be on some ``smaller'' or ``simpler'' argument.

Key idea: There must be one or more base cases to terminate the recursion.

Note direct correspondence to induction.

Recursion in SML

Recursive definitions are introduced by adding the keyword rec after the keyword val:

The effect of rec is to make sure that the right version of f is used; compare:

The expression on the RHS of a val rec must be a function (fn) expression.

The form

is actually a derived form for

More Recursion on Integers

Fibonacci numbers:

Traditional ``for'' loops must be done with recursions.

Sum up the first 10 integers:

Sum up the first 20 Fibonacci numbers:

There's a pattern here: we'll abstract soon...

Recursion on Lists

Computing the maximum of a list of integers:

The need to case over a function argument is so common that there is a special derived form that combines functions and case expressions into one, e.g.

Insertion sort:

Building Lists

Recursive structures must also be built by recursion:

Remember the key ideas!

The ultimate in useless functions:

(``I yam what I yam.'' - Popeye)

Remembering to define the base case(s) is crucial for correctness and termination.

Also helps us understand ``how recursion works.''

If the argument is a data constructor, SML helps us remember base cases:

Multiple base cases

Problem: Given a list of integers, return the same list with zeroes inserted between each.

``Theorem: All cats are the same color.''

Andrew P. Tolmach
Thu Apr 10 18:59:09 PDT 1997