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

Mat*_*iak 48 oop ocaml object

通常,OCaml程序可以在有或没有对象的情况下编写.何时使用物体最有利,何时应避免使用?

gas*_*che 74

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

对象提供了一组:

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

您可以一起使用,也可以单独使用.

根据我的经验,单独使用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
Run Code Online (Sandbox Code Playgroud)

您可以使用对象类型作为结构"类型级别记录"来代替:

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
Run Code Online (Sandbox Code Playgroud)

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

但请注意,这些先进型hackeries的成本相当高; 在使用它们之前,您必须仔细平衡它们带来的额外表现力和静态安全性.

加起来

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

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

  • 当您想要独立提供一组特征/容量的值时,结构类型偶尔会很有用

  • 非常彻底的答案.非常感谢! (4认同)