scala - 为什么 Scala Cats 使用类型类而不是继承?
问题描述
使用类型类而不是继承有什么意义?
Monad
这是一个通过上下文绑定使用类型类的函数:
def f[A : Monad](x:A) = ???
(是的,我们现在得到 flatMap 方法)
但是,这使用带有子类型绑定的继承:
def f[A <: Monad](x:A) = ???
f(x) // where x is a CatsList which implements Monad trait.
(我们现在也得到了 flatMap 方法。)
两者不能达到同样的目的吗?
解决方案
类型类更灵活。特别是,可以轻松地将类型类改造为现有类型。要通过继承做到这一点,您需要使用适配器模式,当您有多个特征时,它会变得很麻烦。
例如,假设您有两个库,它们分别使用继承添加了 traitMeasurable
和:Functor
trait Measurable {
def length: Int
}
trait Functor[A] {
def map[B](f: A => B): Functor[B]
}
第一个库很有帮助地为 List => Measurable 定义了一个适配器:
class ListIsMeasurable(ls: List[_]) extends Measurable {
def length = ls.length
}
第二个库对 List => Functor 做了同样的事情。现在我们想编写一个函数,它接受具有长度和映射方法的东西:
def foo(x: Measurable with Functor) = ???
当然,我们应该希望能够通过它List
。但是,我们的适配器在这里是没有用的,我们必须编写另一个适配器来使其List
符合Measurable with Functor
. 一般来说,如果您有n
可能适用于 的接口,那么List
您就有2^n
可能的适配器。另一方面,如果我们使用了类型类,就不需要第三个类型类实例的额外样板:
def foo[A : Measurable : Functor](a: A) = ???
推荐阅读
- python - 如何在 Pandas 中使用 DateTimeIndex 进行索引
- python - 如何使用依赖项组织我的 git 存储库?
- android - 单击 BottomTabBar 导航上的第一项在 Android 上不起作用
- sql - SQL Server database backup script: How to use parameters for file path/location?
- c++ - 如何在 Windows 中获取光标位置?
- r - 使用紧凑数字引文样式时显示所有使用过的参考文献
- python - Characteristic polynomial of binary matrix over the field F2 or GF(2)
- elasticsearch - 390M 文档/710GB 数据集的 Elasticsearch 集群设计
- html - 将 div 设置为 height: 100% 禁用滚动条
- python - Python - 在 SenseHat 上停止滚动消息