может ли кто-нибудь объяснить мне, почему этот код на лиспе не работает?

#lisp #common-lisp

Вопрос:

он должен подсчитывать элементы списка, но говорит «*** — : НОЛЬ-это не число».

 (setq A '(2 3 4 3 2 6 7 8 4 3 5 6))

(defun big (A) 
   (if (not (null (car A)))   (  1 (big (cdr A)))  )   ;if the first element is not null, add 1 to the count of the elements to the rest of the list
)     
 
(print (big A))
 

Комментарии:

1. Используете ли вы онлайн-интерпретатор для оценки кода Lisp? Какова ваша установка?

Ответ №1:

Ошибка типа

IF Выражение имеет либо 2, либо 3 аргумента:

 (if test something)

(if test something something-else)
 

Когда у него всего 2 аргумента, это как если бы третий аргумент something-else , был равен НУЛЮ. Это означает, что IF выражение равно НУЛЮ, когда test выражение является ложным. В вашем случае у вас есть 2 аргумента:

 (defun big (A) 
  (if (not (null (car A)))
      ;; "then" branch (when condition is true)
      (  1 (big (cdr A)))
      ;; no "else" branch (when condition is false)
      ))
 

Так что вы знаете, что иногда звонок big может вернуться NIL .

Но вы также пишете:

 (  1 (big (cdr A)))
 

Это выражение выглядит как ( 1 x) x вызов big , означающий, что x в некоторых случаях оно может быть равно НУЛЮ. Это тот случай, когда вы столкнулись с отладчиком.

Если вы убедитесь if , что выражение всегда возвращает число, возвращая, например, ноль в ветке else, то у вас не будет той же ошибки при попытке добавить число NIL .

Счетные элементы

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

Когда вы пишете (car a) , вы обращаетесь к первому элементу списка. Затем вы проверяете, не равно ли это значение нулю, но вполне допустимо, чтобы список был заполнен нулевыми значениями:

 '(NIL NIL NIL)
 

Этот список состоит из 3 элементов, и ни в коем случае тот факт, что они равны НУЛЮ, не должен иметь значения при их подсчете.

Рекурсивная функция, работающая со списком, обычно должна охватывать два случая, а именно, пуст ли список или нет. Вы проверяете, пуст ли текущий список, позвонив (null list) или (endp list) (просто (if list ... ...) выполнение тоже работает, так как NIL-единственное ложное значение).

Ответ №2:

Тест на нулевой автомобиль не принесет никакой пользы, cdr вернет ноль до того, как это сделает автомобиль.

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

Для подсчета элементов в списке существует два случая:

Базовый случай, когда список пуст (возвращает 0)

Рекурсивный случай, когда список не пуст (возвращает 1 количество cdr переданного списка)