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.

tex2html_wrap_inline121 Define ``ancestor.''

tex2html_wrap_inline121 Factorial.

tex2html_wrap_inline121 Insertion sort.

tex2html_wrap_inline121 Quick sort.

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

Nearly as bad:


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