In Common Lisp, an atom is anything that isn't a pair, and you can check whether something is an atom with the atom
function. If something is not an atom, then it's a pair, which means that you can call car
and cdr
with it to retrieve the parts of the pair. A simple solution to this, then, is simply:
(defun count-atoms (object)
(if (atom object) 1
(+ (count-atoms (car object))
(count-atoms (cdr object)))))
Note that this counts the nil
terminator of a proper list, so
(a b . c) ;=> 3
(a b . nil) ;=> 3, even though (a b . nil) == (a b)
but this seems to be in line with your description of counting atoms, rather than elements in a list. This implementation does consume stack space, though, so you might have problems with very large structures. You might use a continuation passing approach instead that a Lisp implementation that supports tail call optimization could do with constant stack space:
(defun count-atoms (object)
(labels ((kount (object k)
(if (atom object)
(funcall k 1)
(kount (car object)
(lambda (l)
(kount (cdr object)
(lambda (r)
(funcall k (+ l r)))))))))
(kount object 'identity)))
That continuation passing style avoids using lots of stack space (if the implementation optimizes tail calls), but its not all that transparent (unless you're very accustomed to that style). We can use an explicit stack and a loop to get something that's much more likely to use constant stack space:
(defun count-atoms (object)
(do ((objects (list object)) (natoms 0))
((endp objects) natoms)
(let ((object (pop objects)))
(cond
((atom object) (incf natoms))
(t (push (car object) objects)
(push (cdr object) objects))))))
Now that we have it as a do
loop, it's easy to see how we might write it using tail recursion (what you'd probably do if you were working in Scheme):
(defun count-atoms (object)
(labels ((kount (objects natoms)
(cond
((endp objects)
natoms)
((atom (first objects))
(kount (rest objects) (1+ natoms)))
(t
(kount (list* (car (first objects))
(cdr (first objects))
(rest objects))
natoms)))))
(kount (list object) 0)))