lisp - 列表作为 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 和一个列表 TREE 并检查列表 TREE 中是否存在 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或在函数应用程序中(如 (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 进行比较, 而 =只能用于比较数字。使用 eqeql而不是一般情况:

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

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

(cond ((eq TREE nil) nil)

或更好:

(cond ((null TREE) nil)

文体注释

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

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

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

所以你的函数可能是这样的:

(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

关于lisp - 列表作为 Lisp 中的函数参数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52640068/

相关文章:

lisp - 如何衡量Lisp中方法的效率?

lisp - CLSQL 符号导出

clojure - 是否有可能对 Lisp 家族语言实现自动柯里化(Currying)?

math - LISP 中的计数器变量

functional-programming - letrec 有什么好处?

lisp - 寻找好的 Lisp 代码来阅读

lisp - "Hot"Common LISP 中的调试和交换

lisp - (loop for) 和 (loop :for) in Common Lisp 之间的区别

lisp - Common Lisp 相当于 Racket 的 "module languages"

lisp - GCL中的条件如何处理?