为什么泛型函数与访问器函数lisp

时间:2018-07-27 15:37:11

标签: oop lisp common-lisp clos setf

从我读过的东西中,我了解到CLOS中的Accessor函数允许程序员获取和设置变量,并且它会生成一个通用名称的函数,该名称已赋予访问器,您需要在其中定义不同的方法。但是我想知道的是,为什么泛型函数不能与访问器函数以相同的方式工作?

例如

 (defclass animal ()
       ((sound
         :initarg :sound
         :initform "no sound"
         :accessor make-sound)))

我可以 定义

(defmethod (setf make-sound) ((the-animal animal) value)
       (setf (slot-value the-animal 'sound) value))

但是如果我要带走访问器并添加

(defgeneric (setf make-sound) (the-animal value))

然后在执行以下代码后出现错误。

(setf (make-sound dog) "bark")

除非我重新定义通用函数和方法如下

(defgeneric (setf make-sound) (value the-animal))

 (defmethod (setf make-sound) (value (the-animal animal))
   (setf (slot-value the-animal 'sound) value))

或执行

(setf (make-sound "bark") dog) ;this also works with the accessor

我的问题是为什么会发生?为什么不能用通用函数获得相同的结果?

1 个答案:

答案 0 :(得分:4)

如果没有defmethod表单,则会创建泛型函数

CL-USER 7 > (defclass animal ()
              ((sound
                :initarg :sound
                :initform "no sound")))
#<STANDARD-CLASS ANIMAL 40200ED09B>

请记住:新值首先出现在 SETF函数中。这是由Common Lisp标准定义的。

CL-USER 8 > (defmethod (setf make-sound) (value (the-animal animal))
              (setf (slot-value the-animal 'sound) value))
#<STANDARD-METHOD (SETF MAKE-SOUND) NIL (T ANIMAL) 40200F098B>

CL-USER 9 > (let ((dog (make-instance 'animal)))
              (setf (make-sound dog) "bark")
              dog)
#<ANIMAL 402002187B>

CL-USER 10 > (slot-value * 'sound)
"bark"

似乎可以正常工作。

defclass中,:accessor插槽选项定义了它定义了读取器方法以及具有正确参数列表的相应 setf方法:首先是新值,然后是实例该类的人。