2012-02-20 54 views
8

我正在写一些方法来为各种元素发送HTML。每种方法具有相同的输出,但不一定需要相同的输入。defgeneric中的可选参数?

回送一个game-board需要采取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章节和some CLOS tutorials,但他们没有涵盖我在这里问的情况)。

回答

5

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

Keene's book是我认为对CLOS最全面的指南。不幸的是,它似乎只能以书籍形式提供。

+0

对泛型的函数调度似乎不太令人满意(这会使我回到'echo-board' /'echo-space'/etc。地区)。在这种情况下,我认为你是对的。我可能会更好地定义诸如'echo'(天真地输出单个项目)和单独的'echo-tailored'或类似的(其将基于附加参数改变其输出)之类的东西。 – Inaimathi 2012-02-20 19:27:56

+0

非泛型函数不会进行分派,它只是对参数进行规范化。这显然要求泛型(以及方法)采用所有可能的参数,这就是为什么只有当接口实际上相似时才有用。 – Ramarren 2012-02-21 05:39:34

+0

这是Keene的书的PDF(我不知道这是多么合法,请告知):https://doc.lagout.org/programmation/Lisp/Object-Oriented%20Programming%20in%20Common%20Lisp_% 20A%20Programmer%-27%20Guide%20to%20CLOS%20%5BKeene%201989-01-11%5D.pdf – 2017-07-28 23:56:35

0

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

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

3

只要方法采用相同的参数,但仅在数据类型上有所不同,则更容易。但是,如果通用函数和方法都使用相同的名称(当然),但lambda列表显着不同,那么我个人倾向于使用&关键参数来明确我的意图,而不是使用&可选参数。我认为这对以后的可读性有所帮助。

尝试是这样的(假装我们已经有类A类和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列表(即参数列表)将打破该链。这就是为什么在方法定义中有&键和& allow-other-keys并不特别需要它们。将它们放在DEFGENERIC和方法定义中,可以让我们根据class-b调度方法定义。

免责声明:我自己是Common Lisp的新手,所以请带上一粒盐!