扩展OCaml中的现有类型

ane*_*eal 19 ocaml haskell types type-systems functional-programming

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

type bexp =
  And of bexp * bexp
| Or of bexp * bexp
| Xor of bexp * bexp
| Not of bexp;;
Run Code Online (Sandbox Code Playgroud)

现在让我们说我想在这种类型中添加一个Nop变体,但仅用于新类型 - 有点像继承.嘿,这些应该是代数数据类型,对吧?那么为什么不是这样的:

type nbexp = bexp | Nop nbexp ;;
Run Code Online (Sandbox Code Playgroud)

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

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

Rém*_*émi 19

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

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

type nbexp = [ bexp | `Nop of nbexp ];;
Run Code Online (Sandbox Code Playgroud)

请注意,多态变体比普通变体更棘手,但允许扩展类型.

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


Ale*_*nov 5

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

对。和代数数据类型由标签(又名歧视)工会和产品结构。您想要的只是一个(未标记的)联合,它不是代数数据类型并且 Haskell 不支持。OCaml 具有多态变体(请参阅其他答案)。

Typed Scheme确实支持非标记联合,因此您可能需要检查一下。


har*_*rms 5

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

我想补充一点,代数类型缺乏继承是它们美妙之处的一部分。这意味着And(foo, bar)诸如此类的表达式是明确类型化的,并且强制转换(向上或向下)在类型系统中没有任何作用。这会产生更高的安全性和更高的清晰度。当然,它确实需要程序员明确处理他/他想要与 的bexp部分交互的情况nbexp,但是如果您考虑一下,这就是在实践中实现增加的安全性和清晰度的方式。


use*_*588 5

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

在这里你会做

type bexpr += Nop of bexpr
Run Code Online (Sandbox Code Playgroud)