9

我正在编写一些方法来为各种元素发出 HTML。每种方法都有相同的输出,但不一定需要相同的输入。

呼应a的方法也game-board需要采取a player(因为每个玩家只看到自己的棋子)

(defmethod echo ((board game-board) (p player)) ... )

回显棋盘空间不需要更改每个玩家(该调度实际上是在game-board方法中完成的,该方法稍后会调用echo空间)。理想情况下,我可以做到

(defmethod echo ((space board-space)) ... )
(defmethod echo ((space empty-space)) ... )

还可以想象,我后来遇到了一个对象,该对象需要了解的不仅仅是玩家,才能正确显示自己。但是,由于已经有专门针对相同泛型的方法,因此会出现错误

The generic function #<STANDARD-GENERIC-FUNCTION ECHO (4)> takes 2 required arguments;

返回并命名这些方法似乎不太理想echo-spaceecho-board依此类推。

是否有一种基于专门对象改变其他参数的规范方法?我应该做类似的事情吗

(defgeneric echo (thing &key player ...) ...)

或者

(defgeneric echo (thing &rest other-args) ...)

? 更一般地说,任何人都可以指出我具体的体面教程defgeneric吗?(我已经阅读了相关的 PCL 章节和一些CLOS教程,但它们没有涵盖我在这里询问的情况)。

4

3 回答 3

5

一般来说,如果两个函数的接口相差太大,则表明它们实际上不是同一操作的特化,不应具有相同的名称。如果您只想专注于可选/关键参数,那么实现这一目标的方法是使用一个普通函数,该函数调用一个通用函数并为其提供缺失参数的默认值以进行专门化。

我相信Keene 的书是 CLOS 最全面的指南。不幸的是,它似乎仅以书本形式提供。

于 2012-02-20T06:03:51.447 回答
3

只要方法采用相同的参数但仅在数据类型上有所不同,就会更容易。但是在泛型函数和方法都使用相同的名称(当然)但 lambda 列表差异很大的情况下,我个人倾向于使用 &key 参数来明确我的意图,而不是使用 &optional 参数。我认为它有助于以后的可读性。

尝试这样的事情(假设我们已经有类 class-a 和 class-b):

(defgeneric foo (object &key &allow-other-keys)
  (:documentation "The generic function. Here is where the docstring is defined."))

(defmethod foo ((object class-a) &key &allow-other-keys)
  (print "Code goes here. We dispatched based on type Class A."))

(defmethod foo ((object class-b) &key (x 1) (y 2) &allow-other-keys)
  (print "Code goes here. We dispatched based on type Class B. We have args X and Y."))

由于涉及到“方法组合”,为了让调度逻辑“流动”通过其可能使用的方法选择,我们需要将方法定义想象成一个链,其中不兼容的 lambda 列表(即参数列表)将中断那个链条。这就是为什么在方法定义中有 &key 和 &allow-other-keys 并不特别需要它们的原因。将它们放在 DEFGENERIC 和方法定义中允许我们拥有基于 class-b 调度的方法定义。

免责声明:我自己是 Common Lisp 新手,所以对此持保留态度!

于 2012-04-16T00:17:35.093 回答
0

如何重构对象/类,以便您想要回显的每个对象在其自己的(和继承的)插槽中具有所有必需的属性?

这样,当您在对象上调用 echo 时,您不必将它们作为参数传递,因为您需要的内容已经存储在对象中。

于 2012-02-21T00:23:11.123 回答