Базовая рекурсия LISP, перечислите значения больше 3 - PullRequest
4 голосов
/ 19 ноября 2010

Мне нужна рекурсивная функция LISP, которая перечисляет количество элементов в любом списке чисел> 3. Я не могу использовать let, циклы или whiles и могу использовать только базовые 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))

Ответы [ 3 ]

5 голосов
/ 19 ноября 2010

Некоторые стилистические точки:

  • Нет необходимости вводить некоторые встроенные 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
5 голосов
/ 19 ноября 2010

Ваш код довольно близок к правильному, просто небольшая ошибка в базовом случае:

Для пустого списка вы возвращаете пустой список.Итак, если у вас есть список (6), вы добавляете 6 к foo пустого списка, который является пустым списком.Это не работает, потому что вы не можете добавить число в список.

Вы можете легко исправить это, сделав foo return 0 вместо lst, когда lst пусто.

Как примечание стиля: смешивание cond и if, как это, кажется немного избыточным.Я бы написал так, используя только cond вместо:

(defun foo (lst) 
  (cond
    ((null lst)
      0)
    ((> (car lst) 3) 
      (1+ (foo (cdr lst))))
    (T
      (foo (cdr lst)))))
0 голосов
/ 11 сентября 2018

При дублировании рекурсивного вызова вы можете сохранить одно значение:

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