Type classes似乎很有可能以非常一致、高效和可扩展的方式编写通用和可重用的函数。但是仍然没有“主流语言”提供它们 - 相反:Concepts ,这是一个非常类比的想法,已被排除在下一个 C++ 之外!
反对类型类的理由是什么?显然许多语言都在寻找处理类似问题的方法:.NET 引入了通用约束和接口(interface),如 IComparable
允许类似的功能
T Max<T>(T a, T b) where T : IComparable<T> { // }
对实现接口(interface)的所有类型进行操作。
Scala 改为使用特征组合,即所谓的 implicit parameters/view 边界,自动传递给通用函数。
但是这里显示的两个概念都有很大的缺点 - 接口(interface)是基于继承的,因此由于间接而相对较慢,而且不可能让现有类型实现它们。
如果我们需要一个 Monoid 的抽象,我们可以很好地编写一个接口(interface)并让我们的类型实现它,但是像
int
这样的内置类型永远无法对您的函数进行原生操作。相反,隐式参数与常规接口(interface)/特征不一致。
使用类型类,不会有问题(伪代码)
typeclass Monoid of A where
static operator (+) (x : A, y : A) : A
static val Zero : A
end
instance Int of Monoid where
static operator (+) (x : Int, y : Int) : Int = x + y
static val Zero : Int = 0
end
那么为什么我们不使用类型类呢?他们毕竟有严重的缺点吗?
编辑 : 请不要将类型类与结构类型、纯 C++ 模板或鸭子类型混淆。类型类由类型显式实例化,而不仅仅是按约定满足。此外,它可以携带有用的实现,而不仅仅是定义一个接口(interface)。
最佳答案
概念被排除在外,因为委员会认为它不能及时将它们正确化,并且因为它们不被认为对发布至关重要。不是他们不认为他们是一个好主意,他们只是不认为他们对 C++ 的表达是成熟的:http://herbsutter.wordpress.com/2009/07/21/trip-report/
静态类型试图阻止您将不满足函数要求的对象传递给函数。在 C++ 中,这是一件大事,因为在代码访问对象时,没有检查它是否正确。
概念试图阻止您传递不满足模板要求的模板参数。但是在编译器访问模板参数时,即使没有概念,也已经检查它是否正确。如果您尝试以它不支持的方式使用它,则会收到编译器错误 [*]。在大量使用模板的代码的情况下,您可能会看到三个充满尖括号的屏幕,但原则上这是一条信息性消息。在编译失败之前捕获错误的需求不如在运行时在未定义行为之前捕获错误的需求那么紧迫。
概念使指定将跨多个实例化工作的模板接口(interface)变得更加容易。这很重要,但与指定将跨多个调用工作的函数接口(interface)相比,这是一个不那么紧迫的问题。
在回答您的问题时 - 任何“我实现此接口(interface)”的正式声明都有一个很大的缺点,即它需要在实现之前发明接口(interface)。类型推断系统没有,但它们有一个很大的缺点,即语言通常不能使用类型来表达整个接口(interface),因此您可能有一个对象被推断为正确的类型,但它没有归属于该类型的语义。如果您的语言完全解决接口(interface)(特别是如果它与类匹配),那么您必须在这里采取立场,并选择您的劣势。
[*] 通常。有一些异常(exception),例如 C++ 类型系统目前不阻止您使用输入迭代器,就好像它是前向迭代器一样。为此,您需要迭代器特征。鸭子打字本身并不能阻止你通过一个会走路、游泳和嘎嘎叫的物体,但仔细观察它实际上并没有像鸭子那样做任何这些事情,并且惊讶地发现你认为它会;-)
关于.net - 类型类有什么问题?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1813239/