什么时候应该在OCaml中使用对象?

通常,一个OCaml程序可以写有或没有对象。 什么时候最有利于使用对象,什么时候应该避免?

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

对象提供一束:

  1. 带有和使用函数logging的“标准”风格,可能有多种types
  2. 通过self开放recursion的设施(实现inheritance)
  3. 具有行多态性的结构性,可扩展产品types(用于打开对象types)和子types(用于封闭对象types)

您可以一起使用任何一种,也可以单独使用。

根据我的经验,仅仅点(1)并不是特别值得使用的对象:你可以只使用函数的logging,它也是一样清楚。

使用开放recursion/inheritance的例子

第(2)点恰恰相反是使用面向对象风格的一个很好的理由; 例如Camlp4就是这样使用的:Camlp4定义了折叠AST的类,什么也不做,你可以inheritance这个遍历对象来实现你想要的行为,只需要你想要的语法结构(并且把无聊的遍历pipe道你的母亲class)。

例如,可以扩展Camlp4Ast.map对象,该对象在OCaml抽象语法树的Camlp4表示上定义一个简单的映射函数,recursion地将每个结构映射到自身。 如果你想在(fun x -> e1) e2映射所有的(fun x -> e1) e2expression式来let x = e2 in e1 ,那么你从这个对象inheritance,重载expr方法,只处理你想要的情况(左边是一个函数),委托另一个inheritance的行为。 这会给你一个知道如何在整个程序中recursion地应用这个转换的对象,而不必编写任何样板代码。 如果你愿意的话,你可以进一步扩展这个转换。

有趣的对象types

第(3)点也是将对象用作“可扩展logging”或“types级数组”的理由。 一些使用对象types的库,但不是运行时的对象:它们使用对象types作为幻像types来携带信息,从对对象的更丰富的types级操作中受益。 此外,结构分类允许不同的作者具有兼容的types,而没有强烈依赖于定义他们共享的(名义)types的共同部分; 对象已被用于例如input/输出组件的标准化。

一个非常见的,非常简单的用例是一种习惯的方式来表示具有很多参数的types。 而不是写作:

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

您可以使用对象types作为结构“types级别的logging”来代替:

 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 

为了更高级地使用对象types作为幻像types,可以通过Alec Heller和Jesse Tov来看看ShCaml ( doc )库(它用于表示哪个shell命令与stringinput兼容),或者我的自己的Macaque库( doc和api文档 ),它使用对象types来表示SQL值(包括可空性信息)和表格行types。
多态变体(OCamltypes系统的另一个高级特征;在一个句子中,对象和logging之间的关系与多态变体和代数和types之间的关系相同)也被用作幻像types,例如在这个简单的例子中由理查德琼斯,或检查在Ocsigen框架的HTML文件的有效性。

但是要小心那些高级types的hackeries的复杂性非常高。 在使用它们之前,您必须仔细地平衡它们带来的额外performance力和静态安全性。

加起来

  • 作为一个基本假设,你完全可以不使用对象; 你应该只在你的devise中介绍他们,如果你觉得你缺less的东西,而不是默认的

  • 对象方便打开recursion/inheritance:改进已经在默认/无聊情况下定义的行为

  • 当你想独立地提供一组特性/容量时,结构化types偶尔是有用的