Lisp 推新,无需放置支撑。它被认为是破坏性宏吗?
一个函数和一个宏Lisp 推新,无需放置支撑。它被认为是破坏性宏吗?,lisp,Lisp,一个函数和一个宏 ;; I am sorry for the confusing function name. ;; As one answer suggests, cons-if-not-member is the better name. (defun cons-if-member (element list) (if (member element list) list (cons element list))) (defmacro pushnew-no-bell
;; I am sorry for the confusing function name.
;; As one answer suggests, cons-if-not-member is the better name.
(defun cons-if-member (element list)
(if (member element list)
list
(cons element list)))
(defmacro pushnew-no-bells (element list)
"pushnew without place support"
`(setq ,list (cons-if-member ,element ,list)))
(let ((xx (list 1 2)))
(pushnew-no-bells 0 xx)
xx)
我不知道以下哪项是正确的:
我也不知道pushnew是否被认为是破坏性的,但我想通过首先删除位置支持来简化事情。
pushnew
更改其位置形式的值(第二个参数),因此它是破坏性的:它会“就地”更改某些内容,而不仅仅是创建一个新对象(可能与现有成员共享结构)。您的cons if member
(最好称为cons,除非member
或cons if not member
)不会“就地”修改任何内容,因此实际上是无损的
请注意,顺便说一句,由于存在符号宏,您不能真正排除“常规位置”支持。请注意:
(defclass foo ()
((x :initform nil)))
(let ((instance (make-instance 'foo)))
(with-slots (x) instance
(pushnew-no-bells 1 x))
(format t "~&Now: ~S~%" (slot-value instance 'x)))
pushnew
更改其位置形式的值(第二个参数),因此它是破坏性的:它会“就地”更改某些内容,而不仅仅是创建一个新对象(可能与现有对象共享结构)。如果成员为cons
(最好称为cons,除非成员为或非成员为cons
)不会“就地”修改任何内容,因此它实际上是非破坏性的
请注意,顺便说一句,由于存在符号宏,您不能真正排除“常规位置”支持。请注意:
(defclass foo ()
((x :initform nil)))
(let ((instance (make-instance 'foo)))
(with-slots (x) instance
(pushnew-no-bells 1 x))
(format t "~&Now: ~S~%" (slot-value instance 'x)))
如果成员
不是破坏性的,则不适用。它也大致相当于。pushnew no bells
修改一个位置,但不修改元素可能被推到的列表的结构。但是,它可以修改其他列表的结构,因为您可以将其用作(let((列表(列表1 2 3 4)))(按New no bells'1(cddr列表))
(此外,表单列表
将被评估两次,这不是好的(但也不是此问题/答案的要点)。)这是破坏性的,因为它修改了该位置,但不是破坏性的,例如,nreverse
(nreverse
可以更改cons列表的整个结构)
Hyperspec并没有对破坏性和非破坏性做出完全相同的区分。例如,对于邻接的规范只是说明了它的作用
测试项是否与列表中的现有元素相同。如果该项不是现有元素,则“邻接”将其添加到列表中(如同通过cons)并返回结果列表;否则,不添加任何内容并返回原始列表
另一方面,的文档在其语法部分提到它需要一个位置
pushnew项目位置和关键测试未测试
=>新位置值
说明中提到它有副作用:
新列表已存储到位
副作用:
地点的内容可能会被修改
虽然破坏性和非破坏性捕获了一些关于如何实现事物的一般想法,但实际实现往往更为微妙,因为程序员关心的是哪些事物可能被破坏性修改,以及哪些状态可能被更改
您正在使用的方法(即,对某些操作进行功能实现,然后在其上实现修改宏),但是,它非常好,因为它将帮助您记录哪些函数和宏会产生副作用。它将帮助阅读该文档的任何人了解宏的预期副作用是什么(只需计算函数将要计算的内容,然后将其存储回原处)。如果您正在做大量工作(实际上,如果您正在执行这些操作的话),您可能还应该仔细看看是什么使得实现这些类型的函数/宏对变得非常容易,并将帮助您避免常见的陷阱(如上面对list
的双重评估).如果成员
不是破坏性的,则不适用。它也大致相当于。pushnew no bells
修改一个位置,但不修改元素可能被推到的列表的结构。但是,它可以修改其他列表的结构,因为您可以将其用作(let((list(list 1 2 3 4)))(按New no bells'1(cddr列表))
(此外,表单列表
将被评估两次,这不是好的(但也不是此问题/答案的要点)。)这是破坏性的,因为它修改了该位置,但不是破坏性的,例如,nreverse
(nreverse
可以更改cons列表的整个结构)
Hyperspec并没有对破坏性和非破坏性做出完全相同的区分。例如,对于邻接的规范只是说明了它的作用
测试项是否与列表中的现有元素相同。如果该项不是现有元素,则“邻接”将其添加到列表中(如同通过cons)并返回结果列表;否则,不添加任何内容并返回原始列表
另一方面,的文档在其语法部分提到它需要一个位置
pushnew项目位置和关键测试未测试
=>新位置值
说明中提到它有副作用:
新列表已存储到位
副作用:
地点的内容可能会被修改
而破坏性和非破坏性捕获