Различие между списком и атомом в Common Lisp

У меня есть базовая функция clisp, которую я делаю, которая просто возвращает количество атомов в списке. Проблема, с которой я сталкиваюсь, заключается в том, что мне нужно увеличивать атомы в списке, который находится в списке, вместо того, чтобы видеть список как 1 элемент в списке.

Реальный вопрос, я думаю, заключается в том, как вы различаете в своем коде, является ли элемент списком или атомом? Если я смогу это сделать, я могу отправить списки другой функции, чтобы они сложились и вернули количество содержащихся в них атомов.

Прозрачный как грязь? :)

У меня есть пример здесь:

(defun list_length (a)
  (cond ((null a) 0)
        (t (+ 1 (list_length (cdr a))))))

Это прекрасно работает, если в родительском списке нет встроенных списков, например, '(1 2 3 (4 5) 6) вернет 5. Мне нужно, чтобы он включал 4 и 5 вместо списка (4 5) как один.

Спасибо за вашу помощь.

Джон


РЕДАКТИРОВАТЬ:

(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)

person jmd4931    schedule 05.11.2010    source источник
comment
Потрясающе, это именно то, что я искал. Спасибо sep2k. Но это привело меня к другой проблеме... Вот мой новый код... (defun list_length (a) ( cond (( null a ) 0 ) (( listp ( car a )) ( list_length ( car a ))) (t ( + 1 ( list_length ( cdr a ))))) ) Снова используйте мой пример выше. На самом деле он увидит, что (4 5) — это список, и войдет в него и посчитает эти два атома, но когда он вернется, он забудет о 6 и просто вернется к программе. Таким образом, он добавляет 1 2 3 4 5, а не 6. Я вставлю след ниже.   -  person jmd4931    schedule 05.11.2010
comment
Это было уродливо, разместил код выше. Я отправил сообщение до того, как увидел остальную часть вашего ответа, хотя, сепп, я постараюсь добавить последнюю часть этой строки.   -  person jmd4931    schedule 05.11.2010


Ответы (2)


(listp foo) вернет t, если foo является списком, и nil в противном случае.

Таким образом, вы можете заставить свою функцию list_length обрабатывать вложенные списки, добавив следующий случай к вашему cond:

((listp (car a)) (+ (list_length (car a)) (list_length (cdr a))))
person sepp2k    schedule 05.11.2010

ATOM — это предикат, который вы запрашиваете.

Я рекомендую использовать FLATTEN, стандартную процедуру для выравнивания списков в списках — здесь я представляю одну реализацию.

(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 возвращает список: вы можете запустить LENGTH в списке, чтобы увидеть, сколько атомов у вас получилось.

person Paul Nathan    schedule 05.11.2010
comment
Это отличное предложение, хотя мне, вероятно, не сойдет с рук изменение исходного списка. :( - person jmd4931; 05.11.2010
comment
Вы не меняете оригинал, вы возвращаете новый список. - person Paul Nathan; 05.11.2010
comment
Ты прав. :) Это тоже работает, это определенно другой способ думать об этом, чем мой первоначальный подход. Спасибо за помощь! - person jmd4931; 05.11.2010