列为Lisp中的函数参数

时间:2018-10-04 06:07:42

标签: lisp common-lisp

我有以下代码:

(defun TREE-CONTAINS (N TREE)
  (cond (( = (car TREE) nil) nil)
        (( = (car TREE) N) t)
         (t TREE-CONTAINS (N (cdr TREE)))
  )
)

,它接受数字N和列表TREE,并检查N是否存在于列表TREE中。非常简单,但是由于某些原因,当我调用函数

时,我总是收到此错误
(TREE-CONTAINS 3 '((1 2 3) 7 8))
*** - +: (1 2 3) is not a number

代码有问题吗?我是Lisp的新手,所以也许我只是看不到任何明显的东西..预先感谢!

2 个答案:

答案 0 :(得分:9)

语法错误

您的代码包含一些语法错误,这些错误被标记为编译器警告:

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)中的括号与{{1 }}),但是它们是语法的组成部分,用于指定“语句”的不同部分,例如在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

还有另一个问题:您应该检查列表是否为空,而不是第一个元素为nil。换句话说,第一个条件应该是:

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)

样式注释

  1. 列表是树的一种特殊情况:如果使用术语树,则程序应该更加复杂,并考虑到元素可以是子列表的情况。

  2. 使用小写字母标识符,因为所有内容都转换为大写字母

  3. 将右括号放在表达式的末尾,而不是放在新行上。

所以您的功能可能类似于:

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

答案 1 :(得分:5)

除了可接受的答案外,这是写相同谓词的另一种方式,不带cond

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