Базовая рекурсия LISP, перечисление значений больше 3

StackOverflow https://stackoverflow.com/questions/4220349

  •  26-09-2019
  •  | 
  •  

Вопрос

Мне нужна рекурсивная функция 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
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top