Recursive List Functions
Traditional Lisp textbooks use a variety of short programming exercises to illustrate the behavior of lists and cons cells. Let's just take a moment now to look at two of the better-known examples, then move on.
Our goal in this exercise is to define a function called flatten
that, given a list, undoes any nesting of sublists, causing all elements to be at the top level. For example:
(flatten '(a ((b) c) d)) ⇒ (a b c d)
The solution calls for recursion, flattening the car and the cdr separately, then recombining them in a way that preserves flatness. Suppose the input to flatten
is the list
((a (b)) (c d))
The car is (a (b))
which when flattened yields (a b)
. The cdr is ((c d))
which when flattened becomes (c d)
. The function append
can be used to combine (a b)
with (c d)
and preserve flatness, yielding (a b c d)
. So at the heart of flatten
is this code:
(append (flatten (car lst)) (flatten (cdr lst)))
(I've chosen lst
as the name for flatten
's parameter. I prefer not to use list
, which is the name of a Lisp function.) Now, flatten
is only meant to work on lists, so (flatten (car lst))
is an error if (car lst)
is not a list. We must therefore elaborate as follows:
(if (listp (car lst)) (append (flatten (car lst)) (flatten (cdr lst))))
This if
has no "else" clause. What if (car lst)
is not a list? For example, suppose lst
were
(a ((b) c))
The car, a
, is not a list. In this case, we will simply need to flatten the cdr, (((b) c))
, to get (b c)
; then cons
the car back ...
Get Writing GNU Emacs Extensions now with the O’Reilly learning platform.
O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.