# 15-150: Principles of Functional Programming

# Lecture 4: Recursion and Structural Induction on Lists, Tail Recursion

In the previous lecture, we introduced SML's predefined datatype
`int list` for lists of integers.

An important point is that the list datatype is defined
recursively:

An `int list` is one
of the following (and nothing else):

- Either the empty list
(written
`nil` or `[]`), - or of the form
`x::xs`, with `x : int`
and `xs : int list`.

Last time and today we wrote some functions taking list arguments
and/or returning list values, and we showed how to prove theorems
about lists using structural induction.

We discussed tail recursion, a form of recursion that is somewhat like
the use of loops in imperative programming. This form of recursion is
often used to make functions more efficient.

**Terminology:** A function is *tail
recursive* if it is recursive and if it performs no computations
after any recursive call that it makes. This means in particular that
the function directly returns any value obtained from any recursive
call that it makes. More generally, a function `f` is
said to make a *tail call* to function `g` if calling
`g` is the final computation `f` performs. From that
perspective, a recursive function `f` is tail recursive if any
calls to itself are tail calls.
Accumulator arguments play an important role in tail recursion.
The presence of an accumulator argument in a function forces us to
think carefully about the specification of the function and to prove
corresponding theorems of correctness.

### Key Concepts

- Lists defined recursively
- Correspondence between recursive datatype, recursive function
clauses, and proof by structural induction
- Tail Recursion
- Accumulator argument

(These notes also discuss two concepts that we have not yet
discussed: datatype declarations and structural induction over trees;
we will see these in the next lecture.)