|
Let's think about writing a definition of function length(L) that returns the length of list L. For example, length([2, 4, 6]) = 3 and length([ ]) = 0. There are two key rules about lists that you should always keep in mind when defining functions for lists.
There are two kinds of lists: empty lists and nonempty lists. When thinking about lists, think about each kind.
Every nonempty list has a head and a tail. When thinking about a nonempty list, consider its head and tail.
It suffices to say how to compute the length of an empty list and how to compute the length of a nonempty list. But instead of thinking about an algorithm right now, let's focus on facts, and think about those facts using the conceptual view of lists.
(length.1) | length([ ]) | = | 0 | |
(length.2) | length(L) | = | 1 + length(tail(L)) | (when L ≠ [ ]) |
As you can see, each equation can have a proviso indicating requirements for it to hold; the second equation only holds when L is not empty. The second equation tells you, for example, that length([2, 4, 6, 8]) = 1 + length([4, 6, 8]). Since 4 = 1 + 3, that is true.
We have two facts (equations) about the length function. But what we really want is an algorithm to compute the length of a list. Is it reasonable to say that those two equations define an algorithm? Let's try to compute length([2, 4, 6]) using them. The only thing we do is replace expressions with equal expressions, using facts (length.1) and (length.2) and a little arithmetic.
length([2, 4, 6]) | ||
= 1 + length([4, 6]) | by (length.2), since tail([2, 4, 6]) = [4, 6] | |
= 1 + (1 + length([6])) | by (length.2), since tail([4, 6]) = [6] | |
= 1 + (1 + (1 + length([ ]))) | by (length.2), since tail([6]) = [ ] | |
= 1 + (1 + (1 + 0)) | by (length.1) | |
= 3 | by arithmetic |
Equations (length.1) and (length.2) are easy to convert into C++. Since there are two equations, there are two cases.
int length(const ListCell* L) { if(isEmpty(L)) { return 0; // by (length.1) } else { return 1 + length(tail(L)) // by (length.2) } }It is also okay to use C++ notation directly.
int length(const ListCell* L) { if(L == NULL) { return 0; } else { return 1 + length(L->tail); } }Use whichever form you prefer. But only use C++ notation in C++ function definitions, not in conceptual equations.
Using equations (length.1) and (length.2), show an evaluation of length([6, 5, 4, 3]) by only replacing expressions by equal expressions. Answer
|