I need to find how many elements a given input has. the input can be a list or a symbol, for example:
'a
=> 1 element'(3 . 4)
=> 2 elements'(a b . c)
=> 3 elements'((a b . c) 3 . 4)
=> 5 elements
one problem is that when I'm going through the input, every element can be a list of its own, or a pair (just started learning scheme, so my tools for right now are mainly car/cdr), so, when should I stop my loop? when if (null? x)
condition is true? or maybe when if (null? (car x))
is true?
The title of your question should be changes to how to count atoms in a list structure. There are numerous questions on SE about it. Here is how:
car
and thecdr
applied to the same procedure.1
EDIT
Here's the above algorithm as code:
To comment the comments I've got there are actually 2 more ways to implement this and all of them will give the correct answer to OP's examples. It all has to do with how we interpret
()
to be.Depending on
'(())
should be counted as 0, 1 or 2 elements. Zero since it's all lists without any atoms, 1 since its one list with one null element (not counting null terminator) or 2 since it's the same as a dotted pair with two null elements ((() ())
). It's the last one that my text described, but here are the two other ways: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 callcar
andcdr
with it to retrieve the parts of the pair. A simple solution to this, then, is simply:Note that this counts the
nil
terminator of a proper list, sobut 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:
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:
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):