I have a basic clisp function that I am making that just returns the number of atoms in a list. The issue I am having is I need it to increment for atoms in a list that is in the list, instead of seeing a list as 1 element in the list.
The real question I guess is how do you differentiate in your code whether an element is a list or an atom? If I can do that, I can send the lists to another function to add up and return the number of atoms they contain.
Clear as mud? :)
I have an example here:
(defun list_length (a)
(cond ((null a) 0)
(t (+ 1 (list_length (cdr a))))))
This works great if there are no embedded lists in the parent list, for example,
'(1 2 3 (4 5) 6)
would return 5. I need it to include 4 and 5 instead of the list (4 5) as one.
Thanks for your help.
Jon
EDIT:
(defun list_length (a)
(cond ((null a) 0)
((listp (car a)) (list_length (car a)))
(t (+ 1 (list_length (cdr a))))))
[18]> (list_length '(1 2 3 (4 5) 6))
1. Trace: (LIST_LENGTH '(1 2 3 (4 5) 6))
2. Trace: (LIST_LENGTH '(2 3 (4 5) 6))
3. Trace: (LIST_LENGTH '(3 (4 5) 6))
4. Trace: (LIST_LENGTH '((4 5) 6))
5. Trace: (LIST_LENGTH '(4 5))
6. Trace: (LIST_LENGTH '(5))
7. Trace: (LIST_LENGTH 'NIL)
7. Trace: LIST_LENGTH ==> 0
6. Trace: LIST_LENGTH ==> 1
5. Trace: LIST_LENGTH ==> 2
4. Trace: LIST_LENGTH ==> 2
3. Trace: LIST_LENGTH ==> 3
2. Trace: LIST_LENGTH ==> 4
1. Trace: LIST_LENGTH ==> 5
5
[19]> (dribble)
Lists are single linked lists. In LISP, lists are constructed as a chain of a simple record structure named cons linked together.
Basic Building Blocks in LISPAn atom is a number or string of contiguous characters. It includes numbers and special characters. A list is a sequence of atoms and/or other lists enclosed in parentheses. A string is a group of characters enclosed in double quotation marks.
Lisp has one: everything is a list. The first element is a function name, and the rest are its arguments. Thus, the language is simply a collection of compile- and run-time functions, trivially extensible.
Lists are built up from smaller pieces in Lisp. The dot notation indicates those smaller pieces.
(listp foo)
will return t
if foo
is a list and nil
otherwise.
So you can make your list_length
function handle nested lists by adding the following case to your cond
:
((listp (car a)) (+ (list_length (car a)) (list_length (cdr a))))
ATOM is the predicate you are asking for.
I recommend using FLATTEN, a standard routine to flatten lists in lists - I present one implementation here.
(defun flatten (x)
"descend into the supplied list until an atom is hit.
append the atom to the flattened rest"
(if (endp x)
x
(if (atom (car x ))
(append (list (car x)) (flatten (cdr x)))
(append (flatten (car x)) (flatten (cdr x ))))))
Flatten returns a list: you can run LENGTH on the list to see how many ATOMS you wound up with.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With