|
The flatten code is very simple. You can probably guess what defun is, but you have to know what is cond, atom, and the symbol nil (and its relation to lists), as well as the mapcan function, not to mention the #' notation that appears on the self-reference to flatten. cond is a multi-branch conditional test: it has the syntax (cond (test0 code ...)
(test1 code ...)
(test2 code ...)
...)
The tests are evaluated in sequence. When the first one is encountered that yields true, then the associated code is evaluated. cond then terminates, and yields the value of the last expression that was evaluated.A catch-all clause, if necessary, is put at the end, where the test expression is just the symbol t. This symbol is Lisp's canonical representation of Boolean true. Though, any object other than nil is true, it is good form to use the t symbol as a Boolean true constant. Such a catch-all clause appears in the flatten implementation's cond. atom tests whether a value is an atom, which means "not a cons cell". All objects that are not conses are atoms.
Non-empty lists are made of conses: a three element list has three conses. The empty list is made of no conses; it is represented by the symbol nil, which is an atom. null tests whether a value is the nil object: (null X) is the same thing as (eq nil X). list is a constructor that makes a list of its argument values. mapcan projects a each element of a list through a function. The values returned by the function must be lists, and those lists are catenated together. The catenated list is returned by mapcan (destructively, not functionally!) Obviously, mapcan is relevant to implementing flatten. The #'X notation is a shorhand for (function X). It's a special operator which obtains a function as a value, given its name. It is necessary due to the two-namespace nature of Common Lisp: function bindings are in a separate namespace from variable bindings. If there is a function called X, the (X ...) expression calls the function well enough, but the expression X doesn't retrieve the X function; it refers to an X variable. (function X) refers to the function as a value, and because that is verbose, it has a #'X shorthand. Note that the flatcan expression recurses on the list elements without regard for whether they are lists or not. For instance, if we flatten (1 2 3), then flatten will get recursively called for 1, 2, and 3. These 1, 2, 3 cases will be detected by the (atom structure) branch of the cond. (1), (2) and (3) will be returned, which get catenated by mapcan to (1 2 3) again. |