Scala类型类并且不具备继承性

时间:2016-05-19 17:27:23

标签: scala scala-cats

我目前正在编写一些实现类型类的类。我为此目的使用猫。在此设置中,我有课程A[T]B[T] <: A[T]A[T]是一个monad,因此在导入正确的库时,我可以编写

val x: A[Int] = ???
x.flatMap(_)

但我不能写

val x: B[Int] = ???
b.flatMap(_)

因为scala没有找到flatMap运算符。 相反,我必须写

val x: B[Int] = ???
(b: A[Int]).flatMap(_)

为此工作。这很尴尬,因为我希望子类继承超类的方法。

为了完整起见,我添加了一个没有依赖关系的最小示例,显示了该问题。在此,Filterable是一个类型类,由S实现。

object StackOverflowTest {
  class S[+T]

  class Q[+T] extends S[T]

  trait Filterable[F[+_]] {
    def filter[A](x: F[A]): F[A]
  }

  implicit class FilterOps[F[+_], A](y: F[A])(implicit ev: Filterable[F]) {
    def filter: F[A] = ev.filter(y)
  }

  implicit object SIsFilterable extends Filterable[S] {
    def filter[A](x: S[A]): S[A] = x
  }

  //def failing = {
  //  val q = new Q[Int]()
  //  val r = q.filter
  //}

  def working = {
    val q = new Q[Int]()
    val r = (q: S[Int]).filter
  }
}

failing定义无法编译,因为找不到q.op。另一方面,working通过首先转换为S来缓解此问题。我该怎么做才能使failing示例适用于我的库用户?你必须转换为父类型才能使用它的方法,这感觉非常不自然。

注意,我无法定义实现Filterable[Q]的第二个隐式对象,因为(new Q[Int]()).filter应该是S[Int]类型而不是Q[Int]

1 个答案:

答案 0 :(得分:1)

尝试将SIsFilterable替换为:

implicit def sOrSubtypeIsFilterable [T[+_] <: S[_]] = new Filterable[T] {
  def filter[A](x: T[A]): T[A] = x
}