第一个问题,以及报错信息的原因Undefined function B是cond表单中的一些测试表单试图调用一个尚未定义的函数b .在cond 表单中评估测试表单,并使用结果来确定应该使用哪个分支。在评估 (b T) 或 (b nil) 时,预计 b 是一个函数或宏。相反,您应该在此处使用计算结果为真值或 nil 的表达式。
在调用cdr:(cdr L nil) 和(cdr L T) 周围还有一个括号放错的问题。
一旦这些问题得到解决,代码如下所示:
(defun revList (L b)
(cond ((null L) nil)
(b
(append (revList (cdr L) nil)
(list (car L))))
(t
(append (revList (cdr L) t)
(list (car L))))))
我将使用一些更好的名称重写上面的函数,以使事情更清楚一点。请注意,将 else 子句引入 cond 表单的惯用方式是在最后一个子句中使用 t 作为测试表单:
(defun rev-helper-1 (xs reverse-p)
(cond ((null xs) nil)
(reverse-p
(append (rev-helper-1 (cdr xs) nil)
(list (car xs))))
(t
(append (rev-helper-1 (cdr xs) t)
(list (car xs))))))
此代码编译并运行,但可能没有达到预期的效果。当reverse-p 为真时,代码的作用与它为假时完全相同,只是reverse-p 的意义被翻转了。所以代码总是反转它的输入:
CL-USER> (rev-helper-1 '(1 2 3 4) t)
(4 3 2 1)
CL-USER> (rev-helper-1 '(1 2 3 4) nil)
(4 3 2 1)
此外,此代码不会下降到嵌套列表中:
CL-USER> (rev-helper-1 '(1 2 3 4 (a b c d (5 6 7 8))) nil)
((A B C D (5 6 7 8)) 4 3 2 1)
从 OP 帖子中并不完全清楚所需的目标是在交替的递归调用中反转列表元素,还是在交替的嵌套级别中反转列表元素>。我怀疑第二个目标是正确的。
反向递归调用
要在交替递归调用中反转列表元素,只要在非反转调用中,代码需要将列表的第一个元素重新置于列表“反转”其余部分的前面。这样,所有其他元素都会被移到列表的后面,而那些移到后面的元素将在最终列表中以相反的顺序排列。
(defun rev-helper-2 (xs reverse-p)
(cond ((null xs) nil)
(reverse-p
(append (rev-helper-2 (cdr xs) nil)
(list (car xs))))
(t
(cons (car xs)
(rev-helper-2 (cdr xs) t)))))
CL-USER> (rev-helper-2 '(1 2 3 4) t)
(2 4 3 1)
在嵌套的交替级别中反转
要在交替的嵌套级别中反转,代码需要区分输入中的原子和列表。
如果列表的第一个元素是原子,并且当前级别是反转级别,则第一个元素被包装在列表中并附加到反转级别其余部分的结果。否则,如果第一个元素是一个原子,并且当前关卡不是一个反转关卡,那么第一个元素被 consed 到“反转”关卡其余部分的前面。在第二种情况下,“反转”关卡的其余部分不会改变该关卡中元素的顺序,因为reverse-p 对于非反转关卡将是假的;但是代码仍然需要遍历列表以查看此级别的任何元素是否是需要进一步处理的列表。
否则,第一个元素是一个列表。如果当前级别是反转级别,则第一个元素必须“反转”,即由反转函数处理,然后包装在列表中并附加到反转列表其余部分的末尾。否则当前级别不是反转级别,因此第一个元素必须由反转函数处理并consed到“反转”列表其余部分的前面。
(defun rev-helper-3 (xs reverse-p)
(cond ((null xs) nil)
((atom (car xs))
(if reverse-p
(append (rev-helper-3 (cdr xs) t)
(list (car xs)))
(cons (car xs)
(rev-helper-3 (cdr xs) nil))))
(reverse-p
(append (rev-helper-3 (cdr xs) t)
(list (rev-helper-3 (car xs) nil))))
(t
(cons (rev-helper-3 (car xs) t)
(rev-helper-3 (cdr xs) nil)))))
使用let 表单将(car xs) 和(cdr xs) 的结果绑定到几个描述性标识符,减少了对car 和cdr 的调用次数,并使这更易于阅读:
(defun rev-helper-4 (xs reverse-p)
(if (null xs) nil
(let ((first (car xs))
(rest (cdr xs)))
(cond ((atom first)
(if reverse-p
(append (rev-helper-4 rest t)
(list first))
(cons first
(rev-helper-4 rest nil))))
(reverse-p
(append (rev-helper-4 rest t)
(list (rev-helper-4 first nil))))
(t
(cons (rev-helper-4 first t)
(rev-helper-4 rest nil)))))))
让我们编写一个方便的函数来更好地调用rev-helper-4:
(defun rev-alt (xss)
(rev-helper-4 xss t))
CL-USER> (rev-alt '(1 2 3 4))
(4 3 2 1)
CL-USER> (rev-alt '(1 2 3 4 (a b c d)))
((A B C D) 4 3 2 1)
CL-USER> (rev-alt '(1 2 3 4 (a b c d (5 6 7 8))))
((A B C D (8 7 6 5)) 4 3 2 1)
CL-USER> (rev-alt '(1 (2 3) (4 (5 6)) (7 (8 (9 10)))))
((7 ((9 10) 8)) (4 (6 5)) (2 3) 1)