2

是否可以像函数一样定义结构的插槽之一并访问该插槽以使用该函数?如果是,如何使用它?例如,像这样:

(defstruct problem
   state
   (player (defun getplayer (some-state) (findplayer 1 some-state))) 
   (points (defun getpoints (some-state someplayer) (findpoints someplayer some-state)))
 )
4

3 回答 3

2

你写的东西不起作用,但你可以这样做:

(defstruct problem () state)
(defgeneric getplayer (problem)
  (:method ((p problem))
    (find-player 1 (problem-state p))))
(defgeneric getpoints (problem player)
  (:method ((p problem) player)
    (findpoints player (problem-state p))))
于 2013-11-11T19:18:32.050 回答
2

您还可以做一些漂亮的事情:

(defclass get-player ()
  ((state :initarg :state :accessor state-of))
  (:metaclass sb-mop:funcallable-standard-class))

(defmethod initialize-instance :after ((this get-player) &rest initargs)
  (declare (ignore initargs))
  (sb-mop:set-funcallable-instance-function
   this (lambda ()
          (format t "~&I am: ~s, my state is: ~s" this (state-of this)))))

(let ((get-player (make-instance 'get-player :state :initial-state)))
  (funcall get-player)
  (setf (state-of get-player) :advanced-state)
  (funcall get-player))

;; I am: #<GET-PLAYER {10036104BB}>, my state is: :INITIAL-STATE
;; I am: #<GET-PLAYER {10036104BB}>, my state is: :ADVANCED-STATE

也就是说,您可以拥有函数对象,您可以在其中控制它们捕获的变量。因此,由于您实际上并不需要problem在示例代码中调用的实例getplayer(您只需要state),因此这种方法可能会很有趣。

于 2013-11-11T23:09:26.543 回答
2

我会使用以下两种技术之一:

第一种是存储命名函数的符号,而不是在槽中存储函数。请注意,这假定命名函数在结构 def 本身之外的其他地方定义。

(Defstruct problem
  State
 (Points 'getpoints)
 (Player 'getplayer))

这可以以类似于以下方式使用:

 (Defvar p (make-problem ...))
 (Funcall (problem-points p) x)
 (Funcall (problem-player p) x y)

这样做的原因是,当提供一个符号时,Funcall 会在调用之前自动解析它的 fdefinition。第二种方法非常相似,但不是表示命名函数的符号,而是将槽直接设置为匿名函数(称为“lambda 表达式”)。这种方法与您列出的示例具有额外的相似性,我认为分配给槽值的函数是在结构的定义或实例化中定义的,并且不依赖于在其他地方定义的该函数。所以:

(Defstruct problem
  State
 (Points (lambda (arg0) (some-computation arg0)))
 (Player (lambda (arg0 arg1) (other-computation arg0 arg1))))

进而:

 (Defvar q (make-problem ...))
 (Funcall (problem-points q) x)
 (Funcall (problem-player q) x y)

希望这有帮助!

于 2013-11-13T00:20:42.080 回答