Common Lisp中delete-if与搭配setf的remove-if行为差异大的原因是什么
Common Lisp 中 delete-if 未修改原列表的原因说明
核心原理
Common Lisp 标准明确规定:delete-if 这类破坏性序列操作,仅允许实现复用原序列的内存空间构造过滤后的结果,不保证会修改原变量的绑定指向。你遇到的表现完全符合规范,是对破坏性操作的常见理解误区。
具体问题分析
你的测试代码中需要删除的(cons 1 2)正好是列表*c1*的头元素:
- 列表本质是单向链表,头节点被删除时,不可能通过修改原链表的节点内容来改变原变量的指向,只能返回新的头节点作为操作结果
- 你没有将
delete-if的返回值赋值给*c1*,所以*c1*的绑定始终指向原列表的头节点,打印结果自然和操作前一致
正确用法
破坏性序列操作的返回值必须赋值给原变量才能保证符合预期,和remove-if的用法完全一致:
;; 正确的 delete-if 写法 (setf *c1* (delete-if (lambda (x) (progn (format t "trying to compare ~A ~A~%" x (equal x (cons 1 2))) (equal x (cons 1 2)))) *c1*))
补充注意事项
- 所有Common Lisp的破坏性序列操作(包括
delete、nreverse、nconc等)都需要将返回值赋值回原变量,不能依赖操作自动修改原绑定 - 即使删除的不是头元素,不同实现的破坏性操作行为也可能存在差异,只有拿返回值赋值才能保证跨实现的兼容性
内容的提问来源于stack exchange,提问作者ruby_object
相关产品推荐
相关产品推荐

