我目前正在编写一些实现类型类的类。我为此目的使用猫。在此设置中,我有课程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]
。
答案 0 :(得分:1)
尝试将SIsFilterable
替换为:
implicit def sOrSubtypeIsFilterable [T[+_] <: S[_]] = new Filterable[T] {
def filter[A](x: T[A]): T[A] = x
}