55

通常,可以使用或不使用对象来编写 OCaml 程序。什么时候使用对象最有利,什么时候应该避免使用?

4

1 回答 1

83

作为一般经验法则,不要使用对象。它们带来的额外复杂性通常并不值得。我认为这也是适用于其他语言的规则,但这是另一回事。至少对于 OCaml,人们可以客观地(没有双关语)说,除了极少数情况外,通常的做法是不使用对象。

对象提供一组:

  1. 一种“标准”风格,用于携带和使用函数记录,可能具有多态类型
  2. self通过(实现继承)开放递归的设施
  3. 具有行多态性(对于开放对象类型)和子类型(对于封闭对象类型)的结构化、可扩展产品类型

您可以一起或单独使用其中的任何一个。

以我的经验,仅第 (1) 点并不特别值得使用对象:您可以只使用函数的记录,这同样清楚。

开放递归/继承的用例

相反,第 (2) 点是使用面向对象风格的一个很好的理由;例如,Camlp4 以这种方式使用它:Camlp4 定义了折叠 AST 的类,什么都不做,您可以继承此遍历对象以仅在您想要的句法结构上实现您想要的行为(并将无聊的遍历管道推迟到你的妈妈班)。

例如,可以扩展Camlp4Ast.map对象,该对象在 OCaml 抽象语法树的 Camlp4 表示上定义了一个简单的映射函数,只是将每个构造递归地映射到自身。如果你想,比如说,将所有(fun x -> e1) e2表达式映射到let x = e2 in e1,你从这个对象继承,并覆盖该expr方法,只处理你想要的情况(左侧是一个函数),将另一个委托给继承的行为。这将为您提供一个对象,该对象知道如何递归地在完整程序上应用此转换,而无需编写任何样板代码;如果您愿意,您可以通过其他行为进一步扩展此转换。

对象类型的乐趣

第 (3) 点也是将对象用作“可扩展记录”或“类型级数组”的理由;一些库使用对象类型,但在运行时不使用对象:它们使用对象类型作为幻像类型来携带信息,这得益于您可以对对象进行的更丰富的类型级操作。此外,结构类型允许不同的作者拥有兼容的类型,而不会强烈依赖于定义他们共享的(名义)类型的公共组件;例如,对象已用于输入/输出组件的标准化。

一个不常见的、非常简单的用例是表示具有大量参数的类型的惯用方式。而不是写:

type ('name, 'addr, 'job, 'id) person = ....
val me : (string, string, Job.t, Big_int.big_int) person

您可以使用对象类型作为结构“类型级记录”来编写:

type 'a person = .... constraint 'a = < name:'n; addr:'a; job:'j; id:'i >
val me : < name:string; addr:string; job:Job.t; id:Big_int.big_int > person

为了更高级地使用对象类型作为幻像类型,您可以查看 Alec Heller 和 Jesse Tov 的ShCaml ( doc ) 库(用于表示字符串输入与哪些 shell 命令兼容),或者我的自己的Macaque库(docapi doc),它使用对象类型来表示 SQL 值(包括可空性信息)和表行类型。
多态变体(OCaml 类型系统的另一个高级特性;一句话,对象和记录之间的关系与多态变体和代数和类型之间的关系相同)。也被用作幻像类型,例如在这个简单的例子中由 Richard Jones 编写,或检查Ocsigen框架中 HTML 文档的有效性。

但是请注意,这些高级类型的黑客需要付出巨大的复杂性成本;在使用它们之前,您必须仔细平衡它与它们带来的额外表现力和静态安全性。

加起来

  • 作为一个基本假设,您完全不使用对象是安全的;如果您觉得缺少某些东西,您应该只在您的设计中引入它们,而不是默认情况下

  • 对象便于开放递归/继承:改进在默认/无聊情况下已经定义的行为

  • 当您想独立地对值进行推理时,结构类型有时很有用,提供一组特性/能力

于 2012-05-28T07:10:17.240 回答