为什么要避免子types?

我看到很多Scala社区的人build议避免“瘟疫”这样的分类。 什么是反对使用子types的各种原因? 有什么select?

types决定了组成的粒度,即可扩展性。

例如,一个接口,比如Comparable,它将相等的运算符和关系运算符相结合。 因此,不可能仅仅构成等式或关系接口之一。

一般来说,inheritance的替代原则是不可判定的。 罗素的悖论意味着任何可扩展的集合(即不列举每种可能的成员或子types的types)都可以包括自身,也就是说,它本身就是一个子types。 但是,为了确定(决定)什么是亚型而不是其本身,不variables本身必须被完全列举,因此不再是可扩展的。 这是子类可扩展性使得inheritance不可判定的悖论。 这个悖论必须存在,否则知识将是静态的,从而不存在知识的形成 。

函数组合是子types的完全替代,因为函数的input可以代替它的输出,也就是任何输出types被期望的地方,inputtypes可以被replace,通过包装在函数调用中。 但是组合并不构成子types的双射合同 – 访问函数输出接口,不访问函数的input实例。

因此,合成不必维护未来 (即无界)不variables,因此可以是可扩展的和可判定的。 如果子types可certificate是可判定的,则子types可能更加强大,因为它维护这个双重约定,例如,对超types的不可变列表进行sorting的函数可以在子types的不可变列表上操作。

所以结论是枚举每个types的所有不variables(即它的接口),使这些types正交(最大化合成粒度),然后使用函数合成来完成那些不variables不会正交的扩展。 因此,子types仅适用于对超types接口的不variables进行build模的情况,并且子types的附加接口可certificate与超types接口的不variables正交。 因此接口的不variables应该是正交的。

类别理论为每个子types的不variables模型提供了规则 ,即Functor,Applicative和Monad,它们保留了提升types的函数组合 ,也就是前面提到的列表的子types化的例子。

其中一个原因是当涉及到子typesinput时,equals()非常难以正确使用。 请参阅如何使用Java编写等式方法 。 具体而言,“陷阱#4:未能将等同关系定义为等价关系”。 本质上说:为了在子打字的情况下获得平等,你需要双重调度。

我认为一般情况下,语言要尽可能“纯”(即尽可能使用纯函数 ),并且来自与Haskell的比较。
从“ 程序员的思考 ”

作为混合OO-FP语言的Scala必须处理像子types(Haskell没有的)这样的问题。

正如在这个PSE中提到的答案 :

没有办法限制一个子types,以便它不能超过它inheritance的types。
例如,如果基类是不可变的并且定义了一个纯粹的方法foo(...) ,那么派生类不能是可变的,或者用一个不纯的函数来覆盖foo()

但实际的build议是使用适合您当前正在开发的程序的最佳解决scheme。

注重子types,忽略与类,inheritance,面向对象等相关的问题。我们有这样的想法,子types代表了types之间的关系。 例如,typesA和B有不同的操作,但是如果A是B,我们可以使用B上的任何操作。

OTOH使用另一种传统的关系,如果C hasa B,那么我们可以在C上重用B上的任何操作。通常,语言可以让你编写一个更好的语法,a.opOnB代替a.super.opOnB,就像它在案件的组成,cbopOnB

问题是,在许多情况下,有两种以上的方法。 例如,Real可以被embedded在复数中,假设0在虚部上,但是Complex可以通过忽略虚部被embedded到Real中,所以两者都可以被看作是其他子types的一种关系被视为是优选的。 此外,还有更多的可能的关系(例如,使用极坐标表示的theta分量来将Complex看作一个Real)。

在正式的术语中,我们通常把态射说成types之间的这种关系,并且存在与不同属性(例如同构,同态)关系的特殊态射。

在使用子types的语言中,通常在关系上有更多的糖,并且给定了许多可能的embedded,所以当我们使用这个不重要的关系时,我们倾向于看到不必要的摩擦。 如果我们把inheritance,类和OOP带到组合中,问题变得更加明显和混乱。

我的回答并没有回答为什么避免它,但试图给出另一个暗示,为什么它可以避免。

使用“types”可以在现有的types/类上添加一个抽象而不用修改它们。 inheritance用来表示一些类是更抽象的类的特化。 但是对于types类,您可以使用任何现有的类并表示它们都共享一个共同的属性,例如它们是Comparable 。 只要你不关心他们是Comparable你甚至不会注意到它。 只要不使用它们,类就不会inheritance某些抽象Comparabletypes的方法。 这有点像在dynamic语言编程。

进一步阅读:

http://blog.tmorris.net/the-power-of-type-classes-with-scala-implicit-defs/

http://debasishg.blogspot.com/2010/07/refactoring-into-scala-type-classes.html

我不知道Scala,但是我认为曼陀罗'喜欢inheritance的构成'比起其他所有OO编程语言来说都适用于Scala(子types经常和inheritance一样使用)。 这里

比inheritance更喜欢构图?

你会发现更多的信息。

我认为很多Scala程序员都是以前的Java程序员。 他们习惯于用面向对象的子types来思考,他们应该能够很容易地find面向大多数问题的面向对象的解决scheme。 但function编程是一个新的发现范式,所以人们要求不同的解决scheme。

这是我在这个问题上find的最好的论文。 来自论文的激励报价 –

我们认为虽然面向对象的语言的一些简单方面与ML兼容,但是为ML增加一个完整的基于类的对象系统导致了一个过于复杂的types系统和相对较less的expression增益