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 no bells是破坏性宏,则为cons

  • 两者都是非破坏性的

  • 如果成员是非破坏性函数且形容词“破坏性”和“非破坏性”不适用于宏,则为cons

  • 以上都没有


  • 我也不知道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项目位置和关键测试未测试
    =>新位置值

    说明中提到它有副作用:

    新列表已存储到位

    副作用:
    地点的内容可能会被修改

    而破坏性和非破坏性捕获