2009-11-17 92 views
19

我最近一直在做一些OCaml编程,以学习语言和熟悉函数式编程。最近,我开始想,我希望能够扩展现有的类型(内置,还是我自己的一个),例如:在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中是可行的吗(也许是类型类)?

+1

的也许感兴趣:https://sites.google.com/site/ocamlopen/ – 2013-04-17 20:46:30

回答

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

我听说过这些,但要真正使用还没有得到身边他们。这给了我一个很好的实践理由来了解更多关于它们的信息。谢谢。 – aneccodeal 2009-11-17 16:05:31

4

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

没错。 algebraic data types由标记(又名歧视)工会和产品构建。你想要的只是一个(无标记的)联合,它是而不是的代数数据类型,Haskell不支持。 OCaml具有多态变体(请参阅其他答案)。

Typed Scheme确实支持未标记的联合,因此您可能需要检查它。

4

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

我想补充一下,代数类型的继承性的缺乏是他们精彩的一部分。这意味着诸如And(foo, bar)这样的表达式是无意义的类型,并且该类型(无论是向上还是向下)在类型系统中不起作用。这会产生更大的安全性和更高的清晰度。当然,要求程序员明确地处理他/她想要与nbexpbexp部分进行交互的情况,但是如果你仔细想想,那就是在实践中如何提高安全性和清晰度。

相关问题