扩展OCaml中的现有类型

时间:2009-11-17 05:15:44

标签: haskell types functional-programming ocaml type-systems

我最近一直在做一些OCaml编程来学习语言并且更熟悉函数式编程。最近,我开始认为我希望能够扩展现有类型(内置或我自己的类型),例如:

type bexp =
  And of bexp * bexp
| Or of bexp * bexp
| Xor of bexp * bexp
| Not of bexp;;

现在假设我想在此类型中添加Nop变体,但仅用于新类型 - 有点像继承。嘿,这些应该是代数数据类型,对吧?那么为什么不能这样:

type nbexp = bexp | Nop nbexp ;;

...但这不是有效的OCaml,它给出了语法错误。基本上,我想要做的就是说我希望nbexp包含bexp包含的所有内容,并为此添加一个Nop。我想这是不可能的,因为,例如,如果您使用And构造函数,则无法确定它是bexp类型还是nbexp类型。 (我认为构造函数Nop采用nbexp也可能存在问题。)

那么有没有办法在OCaml中做这样的事情?而且,这是否是Haskell中可行的东西(或许有类型类)?

4 个答案:

答案 0 :(得分:19)

一个有趣的解决方案是使用多态变体:

type bexp =
[ `And of bexp * bexp
| `Or of bexp * bexp
| `Xor of bexp * bexp
| `Not of bexp ];;

type nbexp = [ bexp | `Nop of nbexp ];;

请注意,多态变体比普通变体更复杂,但允许扩展类型。

表达式评估的一个有趣示例,带有扩展,使用多态变体可以在ocaml源的测试目录中找到,请参阅svn

答案 1 :(得分:4)

  

嘿,这些应该是代数数据类型,对吧?

右。 algebraic data types由标记(也称为歧视)的联合和产品构成。你想要的只是一个(非标记的)联合,它不是不是代数数据类型,Haskell不支持。 OCaml具有多态变体(参见其他答案)。

Typed Scheme支持未标记的联盟,因此您可能需要查看它。

答案 2 :(得分:4)

正如你自己正确猜测的那样,这在代数类型中是不可能的。我同意Apocalisp的建议,即你可以简单地将nbexp的“继承”部分包装在它自己的构造函数中。

我想补充一点,代数类型的遗传缺乏是他们精彩的一部分。这意味着诸如And(foo, bar)之类的表达式被粗略地键入,并且转换(向上或向下)在类型系统中没有任何作用。这样可以提高安全性和清晰度。它当然要求程序员明确处理他/她想要与bexp nbexp部分进行交互的情况,但如果您考虑一下,那就是增加安全性的方式在实践中实现了清晰度。

答案 3 :(得分:3)

更新:Ocaml现在具有可扩展类型。 http://caml.inria.fr/pub/docs/manual-ocaml/extn.html#sec246

在这里你会做

type bexpr += Nop of bexpr