Recursive Definitions
We can define a recursive definition as a way of constructing new data elements from previous ones, i.e., defining something in terms of a simpler version of the same thing.
There are two parts to it: base case(s) and constructor case(s).
We can look at a binary string as an example. Usually, a binary string is defined as a sequence of 's and 's. An example of the string is the tuple .
But, with recursive definition, we can denote it as nested pairs, such as , where denotes the empty string — in this case, the base case.
A well-known example of a recursive function is the Fibonacci numbers:
Let's now look at another example.
Let's say we want to define a set of strings, , containing left and right brackets that match up: .
Okay, the notation looks funky, but it's a way to denote a set of finite strings, using an asterisk.
So, the base case is the empty string , if we concatenate it to a string it doesn't change anything.
The constructor we have is this:
Okay, so what does it mean?
It says that if and are strings of brackets in , then the string is also in .
Let's see it in action.
We have the base case, that is, both and are empty. What we're left with is just a left and a right bracket: [ ].
If is [ ], and is empty, we have [ [ ] ] as a result.
If is empty, and is [ ], we have [ ] [ ].
And, if both and are [ ], we have [ [ ] ] [ ].
We can also imagine being [ [ ] ], and being empty, then we have [ [ [ ] ] ].
The cases we defined so far are these:
string |
values |
[] |
|
[[]] |
|
[][] |
|
[[]][] |
|
[[[]]] |
|
Now, it can go on forever. But, how do we know that we will get matching brackets?
Well, one way we can look at it is this: if a string starts with ], then it is not going to be a matching brackets string because it has already lost starting with ], it has no pair.
We can assume that strings that start with ] won't be in .
Now, one thing we know is that the only way to get elements in is by applying the constructor, or it's going to come from the base case itself. This is called the extremal clause, everything that's in is obtained from the base case and the constructor.
Our base case for this matching brackets example is the empty sequence, so it definitely doesn't start with ] because it doesn't even start.
And, our constructor rule is , which also doesn't start with ], therefore a string starting with ] is not going to be in .
Structural induction is a method for proving that all the elements of a recursively defined data type have some property.
So, it is proving that a property holds for all in recursively defined set . In order to do that, we need to prove that every element in each base case in has the property ( for each base case ), also that each constructor holds the property ( for each constructor ) as well.
Let's see it using our matching brackets example.
|
Lemma: Every string in has the same number of ]'s and ['s. |
Let be the set of strings with the same number of ]'s and ['s. |
We assume . |
Induction hypothesis is that . |
The base case is , which means that is an empty set. The property holds because we have left brackets and right brackets, so we have an equal number of brackets. So, is true. ✅ |
The constructor step was in the form of , but we're using the variable to stand for the string, so let's use instead. In this case, the constructor step is . |
The number of ]'s in = |
The number of ['s in = |
Because of , the number of left and right brackets in have to be equal. |
Likewise, because of , the number of left and right brackets in have to be equal as well. |
Then, |
Therefore, we realize that is true: |
So, by structural induction, . |
|