Базовая рекурсия LISP, перечисление значений больше 3
Вопрос
Мне нужна рекурсивная функция LISP, которая перечисляет количество элементов в любом списке чисел > 3.Мне не разрешено использовать let, циклы или while, и я могу использовать только базовые CAR, CDR, SETQ, COND, CONS, APPEND, PROGN, LIST...
Это моя попытка использовать функцию:
(defun foo (lst)
(COND ((null lst) lst)
(T (IF (> (CAR lst) 3)
(1+ (foo (CDR lst)))
(foo (CDR lst)) ) ) ) )
Вызов функции:
(foo '(0 1 2 3 4 5 6))
Решение
Ваш код довольно близок к правильному, просто небольшая ошибка в базовом случае:
Для пустого списка вы возвращаете пустой список.Итак, если у вас есть список (6)
, вы добавляете 6 к foo
пустого списка, который и есть пустой список.Это не работает, потому что вы не можете добавить номер в список.
Вы можете легко это исправить, сделав foo
возвращаться 0
вместо lst
когда lst
пусто.
В качестве примечания к стилю:Смешивание cond
и if
подобное кажется немного излишним.Я бы написал это так, используя только cond
вместо:
(defun foo (lst)
(cond
((null lst)
0)
((> (car lst) 3)
(1+ (foo (cdr lst))))
(T
(foo (cdr lst)))))
Другие советы
Некоторые стилистические моменты:
- Нет необходимости писать некоторые встроенные функции Lisp в верхнем регистре.Это уже не 1958 год!
- Но если ты являются собираюсь поместить встроенные слова в верхний регистр, почему бы и нет
DEFUN
иNULL
? - У вас есть
if
внутри последней ветки вашегоcond
.Это излишне.Поскольку цельcond
это условия тестирования, почему бы не использовать их? - Нет необходимости так расставлять закрывающие скобки.В наши дни никто не считает скобки, у нас есть редакторы, сопоставляющие скобки.
- В Lisp есть отдельные пространства имен для функций и значений, поэтому вам не нужно вызывать аргумент.
lst
чтобы избежать конфликта со встроенной функциейlist
.
Если бы вы программировали это по-настоящему, вы бы, конечно, использовали count-if
:
(count-if #'(lambda (x) (> x 3)) '(0 1 2 3 4 5 6))
==> 3
Одно сохранение, которое вы можете иметь при дублировании рекурсивного вызова:
(defun foo (l)
(if (null l) 0 ; if list is empty, return 0
(+ (if (> (car l) 3) 1 0) ; else +1 if condition is satisfactory
(foo (cdr l))))) ; plus the result from the rest