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

时间:2012-05-28 04:18:08

标签: oop object ocaml

通常,OCaml程序可以使用或不使用对象编写。何时使用物体最有利,何时应避免使用?

1 个答案:

答案 0 :(得分:73)

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

对象提供了一个包:

  1. 用于携带和使用功能记录的“标准”样式,可能具有多态类型
  2. 通过self(实施继承)开放递归的设施
  3. 具有行多态性(对于开放对象类型)和子类型(对于封闭对象类型)的结构化,可扩展的产品类型
  4. 您可以一起使用,也可以单独使用。

    根据我的经验,单独使用point(1)并不是特别值得使用对象:你可以只使用函数记录,它也很清楚。

    使用开放递归/继承的案例

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

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

    对象类型的乐趣

    Point(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
    

    为了更高级地使用对象类型作为幻像类型,您可以查看ShCamldoc)库(它用于表示字符串输入兼容的shell命令) with)由Alec Heller和Jesse Tov,或我自己的Macaque库(docapi doc),它使用对象类型来表示SQL值(包括可空性信息)和表行类型。
    多态变体(OCaml类型系统的另一个高级特征;在一个句子中,对象和记录之间的关系与多态变体和代数和类型之间的关系相同)。还被用作幻像类型,例如{{3}理查德琼斯,或检查in this simple example框架中的HTML文档的有效性。

    请注意,那些先进型hackeries的成本非常高;在使用之前,您必须仔细权衡它们带来的额外表现力和静电安全性。

    总结

    • 作为基本假设,你根本不使用对象是安全的;你应该只在你的设计中介绍它们,如果你觉得你错过了什么,而不是默认

    • 对象便于打开递归/继承:改进已在默认/无聊案例中定义的行为

    • 当您想要独立提供一组功能/容量来推理值时,结构类型偶尔会很有用