In Scheme, it is not only possible, but commonplace, for a list to be an element of another list. One can have a list within a list within a list within a list, and so on -- there is no fixed upper bound on levels of nesting.
For instance, the list (((a b) c) d (e (f))) -- considered simply as
a datum -- has three elements: ((a b) c), d, and (e
(f)). The first of these elements is a list that has two elements: (a b) and c. The list (a b) has two elements, a and
b. And so on.
If you count the symbols in the list (((a b) c) d (e (f))) using a
``flat'' recursion over the list, you find that only one of the elements of
that list is a symbol:
;;; count-top-level-symbols: determine how many elements ;;; of a given list are symbols ;;; Given: ;;; LS, a list. ;;; Result: ;;; COUNT, a nonnegative integer. ;;; Precondition: ;;; LS is a list. ;;; Postcondition: ;;; COUNT is the number of top-level symbols in LS. (define count-top-level-symbols (lambda (ls) (cond ((null? ls) 0) ((symbol? (car ls)) (+ 1 (count-top-level-symbols (cdr ls)))) (else (count-top-level-symbols (cdr ls))))))
> (count-top-level-symbols '(((a b) c) d (e (f)))) 1
The recursion does not attempt to unpack the contents of any of the
elements of ls as it examines them. Since ((a b) c) is not
itself a symbol, it contributes nothing to the total computed by count-top-level-symbols.
Suppose, however, that we want to write a procedure named count-all-symbols that will be able to determine that there are six
symbols altogether within the datum (((a b) c) d (e (f))) -- a, b, c, d, e, and f. We'll need a
different pattern of recursion for this, one that reflects our interest in
the internal structure of list elements. We call this new pattern
deep recursion.
In deep recursion, whenever we examine a list element, we first consider
the possibility that that element is itself a list. If it is, we write a
recursive procedure call, with the first element as its argument, in
addition to the usual recursive procedure call, which takes the rest of the
list as its argument. Contrast the preceding definition of count-top-level-symbols with the following definition of count-all-symbols:
;;; count-all-symbols: determine how many of the ;;; ultimate constituents of a given list structure are ;;; symbols ;;; Given: ;;; LS, a list. ;;; Result: ;;; COUNT, a nonnegative integer. ;;; Precondition: ;;; LS is a list. ;;; Postcondition: ;;; COUNT is the number of symbols at all levels of LS. (define count-all-symbols (lambda (ls) (cond ((null? ls) 0) ((list? (car ls)) (+ (count-all-symbols (car ls)) (count-all-symbols (cdr ls)))) ((symbol? (car ls)) (+ 1 (count-all-symbols (cdr ls)))) (else (count-all-symbols (cdr ls))))))
> (count-all-symbols '(((a b) c) d (e (f)))) 6
In the definition of count-all-symbols, the second cond-clause, which is new, comes into play when the first element of ls is itself a list. The recursive call (count-all-symbols (car
ls)) counts the symbols that occur inside that first element, while (count-all-symbols (cdr ls)) counts the symbols that occur inside all of
the remaining elements of ls (at any level). The total number of
symbols in ls is found by adding the two counts.
The characteristic signs of deep recursion are (1) the insertion of the new
cond-clause to detect the case in which the first element of a list
is itself a list, and (2) the dual recursive procedure calls, one to deal
with the car and the other with the cdr of the given list.
We refer to the number of nested lists within which a datum is enclosed as its nesting level. The depth of a nested list of symbols is the maximum nesting level of any of the symbols that occur in it. Here is a procedure that computes the depth of a nested list of symbols:
;;; depth: compute and return the maximum nesting level of ;;; a given nested list ;;; Given: ;;; LS, a list. ;;; Result: ;;; DEPTH, a nonnegative integer. ;;; Precondition: ;;; LS is a list. ;;; Postcondition: ;;; DEPTH is the maximum nesting level of any of the ;;; ultimate components of LS. (define depth (lambda (tr) (cond ((null? tr) 0) ((list? (car tr)) (max (+ 1 (depth (car tr))) (depth (cdr tr)))) ((symbol? (car tr)) (max 1 (depth (cdr tr)))) (else 0))))
I am indebted to Professors Henry Walker and Ben Gum for their contributions to the development of this reading.