Lisp中的函数参数列表

Lisp中的函数参数列表,lisp,common-lisp,Lisp,Common Lisp,我有以下代码: (defun TREE-CONTAINS (N TREE) (cond (( = (car TREE) nil) nil) (( = (car TREE) N) t) (t TREE-CONTAINS (N (cdr TREE))) ) ) 它接受一个数字N和一个列表树,并检查列表树中是否存在N。非常简单,但由于某种原因,我在调用函数时不断遇到这个错误 (TREE-CONTAINS 3 '((1 2 3) 7 8)) *** - +:

我有以下代码:

(defun TREE-CONTAINS (N TREE)
  (cond (( = (car TREE) nil) nil)
        (( = (car TREE) N) t)
         (t TREE-CONTAINS (N (cdr TREE)))
  )
)
它接受一个数字N和一个列表树,并检查列表树中是否存在N。非常简单,但由于某种原因,我在调用函数时不断遇到这个错误

(TREE-CONTAINS 3 '((1 2 3) 7 8))
*** - +: (1 2 3) is not a number

代码有问题吗?我对Lisp很陌生,所以也许我只是没有看到一些非常明显的东西。。提前谢谢

语法错误

您的代码包含多个标记为编译器警告的语法错误:

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
或在函数应用程序中(如
(函数名arg1 arg2…argn)
)。因此,本例中的语法错误出现在最后一行,在最后一行中,您应该调用带有参数
N
(cdr树)
,如下所示:

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.
原因是您使用了
=
将数字(
(汽车树)
)与值
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)))))
    
    检查树而不是列表的成员资格

    另一方面,如果你想检查一个通用的树,即一个可以包含子列表的列表,比如在<代码>(树包含3个((1个2个3)7个8))< /C>,在递归中你应该考虑列表中的一个元素本身是一个列表,然后执行双递归。

    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
    

    除了公认的答案之外,这里还有一种编写相同谓词的替代方法,不使用
    cond

    (defun list-contains-p (number list)
      (and (consp list)
           (or (= number (first list))
               (list-contains-p number (rest list)))))