我是一个长期的面向对象程序员和函数式编程新手。从我的经验来看,代数数据类型对我来说只是一个继承的特例,你只有一个层次结构,并且超类不能扩展到模块之外。
所以我的问题(可能很愚蠢)是:如果ADT只是继承的一种特殊情况(同样,这个假设可能是错误的;请在这种情况下纠正我),那么为什么继承会受到所有的批评,而ADT会得到所有的赞扬?
谢谢。
发布于 2010-07-17 23:01:38
我认为ADT是对继承的补充。它们都允许您创建可扩展代码,但可扩展性的工作方式是不同的:
面向对象的世界和函数世界都开发了允许另一种类型的可扩展性的方法。在Haskell中,你可以使用类型类,在ML/OCaml中,人们可以使用函数字典或(?)函数来获得继承风格的可扩展性。另一方面,在OOP中,人们使用访问者模式,这本质上是一种获得类似ADT的东西的方法。
通常的编程模式在OOP和FP中是不同的,因此当您使用函数式语言编程时,您编写代码的方式更需要函数式可扩展性(在OOP中也是如此)。在实践中,我认为有一种语言可以让你根据你试图解决的问题同时使用这两种风格,这是很棒的。
发布于 2010-07-18 00:58:24
Tomas Petricek的基本原理是完全正确的;您可能还想看看Phil Wadler关于“表达式问题”的文章。
我们中的一些人更喜欢代数数据类型而不是继承还有另外两个原因:
附言:你在读什么?我不知道有哪个负责任的人会说"ADTs好,OO坏“。
发布于 2010-07-18 02:59:11
根据我的经验,人们通常认为大多数面向对象语言实现的继承“不好”的地方不是继承本身,而是子类修改超类(方法覆盖)中定义的方法的行为,特别是在存在可变状态的情况下。这是真正的最后一部分,这是踢球。大多数面向对象语言将对象视为“封装状态”,这等同于允许对象内部状态的猖獗变化。因此,例如,当超类希望某个方法修改私有变量,但子类覆盖该方法来做完全不同的事情时,就会出现问题。这可能会引入编译器无能为力的细微bug。
请注意,在Haskell的子类多态性实现中,不允许使用可变状态,因此您不会遇到这样的问题。
另请参见this objection到子类型的概念。
https://stackoverflow.com/questions/3271974
复制相似问题