首页 > 解决方案 > 为什么 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 方法。)

两者不能达到同样的目的吗?

标签: scalainheritancefunctional-programmingtypeclassscala-cats

解决方案


类型类更灵活。特别是,可以轻松地将类型类改造为现有类型。要通过继承做到这一点,您需要使用适配器模式,当您有多个特征时,它会变得很麻烦。

例如,假设您有两个库,它们分别使用继承添加了 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) = ???

推荐阅读