【问题标题】:Define function inside a structure with defstruct使用 defstruct 在结构内定义函数
【发布时间】:2013-11-11 18:30:09
【问题描述】:

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

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

【问题讨论】:

  • 不,你不能这样做。我想你可能想看看 CLOS,你可以在其中定义访问槽的方法。
  • 你写的内容的预期语义是什么? getplayergetpoints 的参数应该是什么?
  • 这可能取决于您到底想要达到什么目标。您可以将实际函数放入插槽的initform 中(这将导致每次实例化结构时都会创建它。您可以在结构上专门化该函数。您也可以使用类,在这种情况下您也可以创建funcallable 类,因此将所有 OO 机制应用于函数本身。

标签: lisp common-lisp


【解决方案1】:

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

第一个方法是存储命名函数的符号,而不是在槽中存储函数。请注意,这假定命名函数在结构 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)

希望对您有所帮助!

【讨论】:

  • 谢谢!这就是我想知道的!再次感谢您的回答! ;)
【解决方案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))))

【讨论】:

    【解决方案3】:

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

    (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),因此这种方法可能会很有趣。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-04-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多