Синтаксические ошибки
Ваш код содержит несколько синтаксических ошибок, помеченных как предупреждения компилятора:
CL-USER> (defun TREE-CONTAINS (N TREE)
(cond (( = (car TREE) nil) nil)
(( = (car TREE) N) t)
(t TREE-CONTAINS (N (cdr TREE)))
)
)
;Compiler warnings :
; In TREE-CONTAINS: Undeclared free variable TREE-CONTAINS
; In TREE-CONTAINS: Undefined function N
TREE-CONTAINS
Причина заключается в том, что скобки в Common Lisp имеют значениеотличается от других языков программирования: они не используются для указания порядка применения операторов (как в 3 * (2 + 4)
, который отличается от 3 * 2 + 4
), но являются неотъемлемой частью синтаксиса для определения различных частей«Оператор», как в cond
или в приложении функции (например, (function-name arg1 arg2 ... argn)
).Таким образом, синтаксическая ошибка в этом случае находится в последней строке, в которой вы должны вызвать функцию TREE-CONTAINS
с аргументами N
и (cdr TREE)
как:
CL-USER> (defun TREE-CONTAINS (N TREE)
(cond (( = (car TREE) nil) nil)
(( = (car TREE) N) t)
(t (TREE-CONTAINS N (cdr TREE)))
)
)
TREE-CONTAINS
Семантические ошибки
Если вы попробуете эту функцию, вы обнаружите ошибку:
CL-USER> (TREE-CONTAINS 2 '(1 2 3))
The value NIL is not of the expected type NUMBER.
Причина в том, что вы использовали =
для сравнения числа ((car TREE)
) сзначение nil
, тогда как =
можно использовать только для сравнения чисел.Используйте eq
или eql
вместо этого для общего случая:
CL-USER> (defun TREE-CONTAINS (N TREE)
(cond (( eql (car TREE) nil) nil)
(( = (car TREE) N) t)
(t (TREE-CONTAINS N (cdr TREE)))
)
)
TREE-CONTAINS
CL-USER> (TREE-CONTAINS 2 '(1 2 3))
T
Существует также другая проблема: вы должны проверить, если список пуст, а не если первый элемент равен нулю.Другими словами, первое условие должно быть:
(cond ((eq TREE nil) nil)
или лучше:
(cond ((null TREE) nil)
Стилистические заметки
Список является частным случаем дерева: если вы используете дерево терминов, программа должна быть более сложной, учитывая случаи, когда элементы могут быть подсписками.
Использовать строчный идентификатор, поскольку все переведено в верхний регистр
Поставьте закрывающие скобки в конце выражения, а не на новой строке.
Таким образом, ваша функция может выглядеть примерно так:
(defun list-contains (n list)
(cond ((null list) nil)
((= (car list) n) t)
(t (list-contains n (cdr list)))))
Проверка членства для дерева, а не для списка
Если, с другой стороны, вы хотите проверить дляобщее дерево, то есть список, который может содержать подсписки, как в (tree-contains 3 '((1 2 3) 7 8))
, в вашей рекурсии вы должны рассмотреть случай, когда элемент списка сам является списком, а затем выполнить двойную рекурсию.Вот возможное решение:
CL-USER> (list-contains 2 '(1 (2 3) 4))
The value (2 3) is not of the expected type NUMBER.
CL-USER> (defun tree-contains (n tree)
(cond ((null tree) nil)
((listp (car tree)) (or (tree-contains n (car tree))
(tree-contains n (cdr tree))))
((= (car tree) n) t)
(t (tree-contains n (cdr tree)))))
TREE-CONTAINS
CL-USER> (tree-contains 2 '(1 (2 3) 4))
T