5

考虑这个例子:

有一个名为“first”的类,它在包“a”中定义。

还有一个使用模块“a”功能的包“b”。包“b”的某些功能需要“first”类的对象作为参数。但除此之外,包“a”和“b”之间没有直接的逻辑联系。

现在我想知道编写(defmethod package-b-function ((param first)) #|do stuff..|#)而不是普通函数是否合理,因为函数需要对象并且定义一个方法将为运行时环境和包'b'的其他用户澄清这一点。

我曾经用 C++/Java 编程,因此我不熟悉在这种情况下使用的 OOP 约定。

欣赏你的洞察力。

4

3 回答 3

9

Common Lisp 中的方法与您注意到的语言的工作方式并不完全相同(有关详细信息,请参阅Practical Common Lisp的相应)。简而言之,在非常高的层次上,您需要将 lisp 中的 OO 视为“方法专门用于类”而不是“类具有方法”。

也就是说,是的,我认为对于一个包来说,拥有一个专门针对在别处定义的类的方法是完全合理的。指定您期望的输入类型可以阐明未来读者的意图(并且可能有助于优化,也可能没有帮助,但从我的角度来看,这并不是非常重要)。如果您正在为您的包定义一个 ASDF 系统,请确保import使用适当的符号和depends-on适当的包。

就像脚注一样,请注意,Common Lisp 作为一种语言并不是特别面向对象的(例如,如果您决定某个特定的类应该具有lengthpoppush方法,或专注于算术运算,您会遇到一些奇怪的角落) .

于 2012-08-03T15:58:05.810 回答
4

Common Lisp 提供普通函数和泛型函数。

作为第一条规则,请使用:

当您想从各种可用方法(例如使用 Mixins 编程时)或当您想根据运行时参数选择方法时,使用泛型函数。

如果您不需要这种高级行为,那么只需使用普通函数即可。记录普通函数需要什么样的参数以及相应的运行时检查可以通过其他 CL 功能来完成:

  • CHECK-TYPE
  • ASSERT
  • 文档字符串
  • DECLARE参数类型
于 2012-08-07T08:02:00.033 回答
1

如前所述,在您描述的场景中,从纯技术 POV 来看,函数和方法都可以正常工作。Inaimathi 的回答(以及您的问题文本)给出了使用的理由defmethod(更好地向读者传达意图,更好的编译器信息)。使用普通函数的一个原因是在设计的早期阶段和探索性编程中都有助于重构。一种常见的 CL 技术是让函数接受仅传递给其他函数的任何参数(例如,在您的情况下,获取/设置槽的访问器a:firstpackage-b-function

如果您创建package-b-function一个函数,您可以更改 class 的名称a:first,将其从一个类更改为一个结构,将它从一个列表更改为一个向量,然后在进行性能测量时返回,您的中间层package-b-function和它的 50 个兄弟将继续工作。如果使用 对类型信息进行编码defmethod,则付出的代价是在更改系统中的基本数据结构时必须更改大量代码,因此您无法轻松回答诸如“如果我使用 5 元素向量,事情会运行得更快”之类的问题而不是这里的物体?” 否则,只需定义 5 个访问器函数来svref代替,slot-value以及调用工厂vector代替make-instance.

于 2012-08-07T07:50:31.020 回答