The following is the famous Fibonacci sequence.
From 2 onwards, each number is the sum of the previous two. This is an example of a recursive definition.
Here we'll see how to define and work with a recursively defined function.
Task
The following is a recursively defined function
Let's see how it works.
- For
, the definition tells us . - For
, the definition tells us . Using , this becomes . - For
, the definition tells us . Using , this gives us . - Try
yourself. You should get .
What makes the definition recursive is that, apart from
Our task is to prove this recursively defined function has a much neater closed form,
Similarity To Induction
It is worth pausing to reflect on the process of calculating each
It looks very similar to the process of induction we saw in the last chapter.
Maths
We'll try a proof by induction. Let
The base case
The inductive step is the implication
- The definition (1) tells us
. - By assumption
, so . - That
simplifies to . - Putting all this together, we have
.
We have shown the base case
Let's write this out as preparation for a Lean proof.
Code
The following Lean program proves, by induction, that
-- 22 - Recursion
import Mathlib.Tactic
def f : ℕ → ℕ
| 0 => 0
| n + 1 => 2 * n + 1 + f n
#eval f 2
example {n: ℕ} : f n = n^2 := by
induction n with
| zero =>
calc
f 0 = 0 := by rw [f]
_ = 0^2 := by norm_num
| succ n ih =>
calc
f (n + 1) = 2 * n + 1 + f n := by rw [f]
_ = 2 * n + 1 + n^2 := by rw [ih]
_ = (n + 1)^2 := by ring
This code is in three parts. Let's look at each in turn.
Definition
The first part is the recursive definition of f.
The f : ℕ → ℕ declares f as a function which maps natural numbers to natural numbers.
Even though the code is new, we can see how it maps 0 to 0, and n + 1 to 2 * n + 1 + f n. Here f n means “f applied to n”, which is just
Our earlier definition (1) mapped
Evaluation
The second part tests our function behaves as we expect.
The #eval is a special instruction which evaluates an expression and prints the answer in the Infoview. Just as #eval 2 + 3 will print 5, #eval f 2 will evaluate the function f applied to 2, and print the answer. Try evaluating f with other parameters.
Proof
The third part is the proof of the proposition f n = n^2.
This proof by induction is not very different to the one we saw in the last chapter.
- The base case needs to prove f 0 = 0 ^ 2. We do this with a calc section. The first step f 0 = 0 is justified by rw [f] which uses the first part of the recursive definition | 0 => 0.
- The inductive step needs to prove f (n + 1) = (n + 1) ^ 2, and also uses a calc section. The first step which equates f (n + 1) with 2 * n + 1 + f n is similarly justified by rw [f], which this time uses the recursive part of the definition.
Recursion & Induction
We saw earlier the similarity between the process of induction and the evaluation of a recursively defined function.
We now see the similarity between the structure of an induction proof and the definition of a recursively defined function.
These similarities are not a coincidence. If you're curious to find out more, search the more advanced guides for recursive types.
Infoview
Placing the cursor after #eval f 2 shows the result of the function f applied to 2.
4
Changing the code to #eval f 3 shows the result of the function f applied to 3.
9
Exercise
The following is a recursively defined function
Write a recursive definition for