Lisp移除列表所有a的代码运行异常,为什么没有输出D元素?
Lisp移除列表中所有a元素的代码问题排查
核心错误原因
你的代码存在两个核心问题,直接导致了D元素丢失:
or逻辑误用:你处理子列表时用了(or (removeA (car arr)) (removeA (cdr arr))),Lisp中or只要第一个参数求值结果非nil就会直接返回该结果,不会执行后续参数。你的测试用例中(v a e)移除a后得到(V E)是非空值,所以or直接返回该结果,完全跳过了对后续列表元素(a a)和d的处理,D自然不会出现在结果里。cond分支结构不规范:你cond的第二个分支只有测试条件(嵌套的if语句)没有对应执行体,虽然cond允许这种写法,会直接返回测试条件的求值结果,但逻辑可读性极差,也容易引发隐藏问题。
修正后代码
按照「递归移除所有层级的a元素,保留非空的列表结构」的需求,修正后的实现如下:
(defun removeA (arr) (cond ;; 列表为空直接返回nil ((null arr) nil) (t (let ((processed-car ;; 先处理当前第一个元素 (if (listp (car arr)) ;; 是子列表就递归处理 (removeA (car arr)) ;; 不是子列表就判断是不是a,是就返回nil,否则返回元素本身 (if (eql 'a (car arr)) nil (car arr))))) (if (null processed-car) ;; 第一个元素处理后为空(要么是a,要么是处理完空的子列表),直接返回处理剩余元素的结果 (removeA (cdr arr)) ;; 第一个元素有效,拼到处理完的剩余列表前面 (cons processed-car (removeA (cdr arr))))))))
测试结果
运行测试语句(print (removeA '(a (a) (v a e) (a a) d))),输出结果为:
((V E) D)
符合预期包含D元素。如果需要保留空的子列表,删除判断processed-car是否为空的分支,直接拼接即可,输出结果会变为(() (V E) () D)。
内容的提问来源于stack exchange,提问作者Leli
相关产品推荐
相关产品推荐

