Lisp 修改函数的参数

Lisp 修改函数的参数,lisp,common-lisp,Lisp,Common Lisp,为什么removef没有真正修改变量?在Common Lisp中,参数是“通过身份”传递的(Allegro Common Lisp实现的开发人员之一)。想象一下指针(到堆对象)是通过值传递的,这对于大多数Lisp对象(比如字符串、向量,当然还有列表)都是如此;事情稍微复杂一些,因为实现可能也有立即值,但这与这里的要点无关 seq的setf修改函数的(私有、词汇)变量绑定。此更改在removef之外不可见 为了使removef能够在调用时影响周围环境,需要将其设置为宏: (setf list (l

为什么
removef
没有真正修改变量?

在Common Lisp中,参数是“通过身份”传递的(Allegro Common Lisp实现的开发人员之一)。想象一下指针(到堆对象)是通过值传递的,这对于大多数Lisp对象(比如字符串、向量,当然还有列表)都是如此;事情稍微复杂一些,因为实现可能也有立即值,但这与这里的要点无关

seq的
setf
修改函数的(私有、词汇)变量绑定。此更改在
removef
之外不可见

为了使
removef
能够在调用时影响周围环境,需要将其设置为宏:

(setf list (loop for i from 1 to 12 collect i))
(defun removef (item seq)
  (setf seq (remove item seq)))


CL-USER> (removef 2 list)
(1 3 4 5 6 7 8 9 10 11 12)

CL-USER> (removef 3 list)
(1 2 4 5 6 7 8 9 10 11 12)
您可能需要了解和了解的概念。注意,上面提供的
removef
I的宏版本是而不是实际应该如何操作!有关详细信息,请阅读及其丑陋的细节

如果您想做的是破坏性地修改列表,请考虑使用<代码>删除>代码>而不是删除,但请注意,这可能有意想不到的后果:

(defmacro removef (element place)
   `(setf ,place (remove ,element ,place)))
ANSI标准不允许(您正在破坏性地修改文字对象,即代码的一部分)。在本例中,错误很容易发现,但如果您在某些调用堆栈中有7帧深,并且处理的值的来源对您来说并不完全清楚,那么这将成为一个真正的问题。不管怎样,甚至

(delete 2 '(1 2 3 4))
一开始可能会令人惊讶,尽管

(setf list (list 1 2 3 4))
(delete 1 list)
list
似乎“工作”。从本质上讲,第一个示例不能按预期工作,因为函数
delete
与原始版本的
removef
存在相同的问题,即它不能更改调用方对
列表
变量的概念,因此即使对于破坏性版本,正确的方法也是:

(setf list (list 1 2 3 4))
(delete 2 list)
list

下面是一个
removef
实现的示例,它“能够在调用点影响周围环境”,如@Dirk所述

(setf list (delete 1 (list 1 2 3 4)))
公用设施和可在项目中使用


顺便说一句,亚历山大港有一个使用但需要辅助定义的定义。此版本不需要辅助定义。

尽管最常见的情况是
define setf expander
removef
如果愿意使用不同的参数顺序,可以更容易地使用。
 (defmacro removef (item place &rest args &key from-end test test-not start end count key &environment env)
    (declare (ignore from-end test test-not start end count key))
    (multiple-value-bind (vars vals store-vars writer-form reader-form)
        (get-setf-expansion place env)
      (assert (length= store-vars 1) ()
              "removef only supports single-value places")
      (let ((v.args (make-gensym-list (length args)))
            (store-var (first store-vars)))
        (once-only (item)
          `(let* (,@(mapcar #'(lambda (var val)
                                `(,var ,val))
                            vars vals)
                  ,@(mapcar #'(lambda (v.arg arg)
                                `(,v.arg ,arg))
                            v.args args)
                    (,store-var (remove ,item ,reader-form ,@v.args)))
             ,writer-form)))))