Lisp 与子列表的混淆

Lisp 与子列表的混淆,lisp,Lisp,我浏览了一个问题的例子,这个问题应该确定非线性列表中任何级别的所有非数值原子的列表 (Defun Lis(L) (Cond ((Null L) Nil) ((Not (Numberp (Car L))) (Cons (Car L) (Lis (Cdr L)))) ((Atom (Car L)) (Lis (Cdr L))) (T (Append (Lis (Car L)) (Lis (Cdr L)))) )

我浏览了一个问题的例子,这个问题应该确定非线性列表中任何级别的所有非数值原子的列表

   (Defun Lis(L)
      (Cond
        ((Null L) Nil)
        ((Not (Numberp (Car L))) (Cons (Car L) (Lis (Cdr L))))
        ((Atom (Car L)) (Lis (Cdr L)))
        (T (Append (Lis (Car L)) (Lis (Cdr L))))
    ))
我举了一个例子,
(Lis'(1a((B)6)(2(c3))d4))
,它应该返回
(abcd)

现在我不明白当对列表的第三个元素进行求值时,如何创建列表。它将进入第二个分支并执行
cons
?但这并不是用
((B)6)
构建新的列表?它将何时进入最后一个分支?我对这个算法的工作原理有点困惑,有人能给我讲清楚吗?

如果您“反转”两个中间测试,代码工作正常:

(defun lis(L)
  (cond
   ((null L)          nil)
   ((numberp (car L)) (lis (cdr L)))
   ((atom (car L))    (cons (car L) (lis (cdr L))))
   (t                 (append (lis (car L)) (lis (cdr L))))))
因为
(not(numberp(car L))
也适用于列表,所以在初始版本中,代码不会递归到子列表中。

我将其写成:

(defun tree-keep-if (predicate tree)
  "Returns the list of all non-numeric atoms at any level in a cons tree."
  (mapcan (lambda (item)
            (cond ((consp item)             (tree-keep-if predicate item))
                  ((funcall predicate item) (list item))
                  ((atom item)              nil)))
          tree))
使用它:

CL-USER > (tree-keep-if (complement #'numberp) '(1 A ((B) 6) (2 (C 3)) D 4))
(A B C D)

更复杂的版本可能会删除不受堆栈大小限制的递归。

当您说它应该返回
(A B C D)
你的意思是因为你是手工执行的,还是你真的在Lisp解释器中计算了你的表达式?结果写在我找到它的那本书中。代码中的括号都错了,所以它不能工作。它似乎也有你提到的bug。如果是书上的,那书上就有错误。(哪本书用这种风格写Lisp?)是的,你关于
((B)6)
的直觉几乎肯定是正确的。书可能是错的。你必须在一个真正的口译员中试一下。然后您可以尝试修复它。:)