我想了一点关于如何解决这个问题。基本上,即使只有超类型是函子,我们也希望提供函子操作。似乎无法表达某些更高种类的类型是另一种类型的超类型,例如,这样的事情是不可能的:def bla[F[_], R[_] <: F]
然而,我们可以隐式地提供从 R[ ] 到 F[ ] 的转换以及 B 的函子:
abstract class ProvidesFor[R,F[_],FF[_[_]],A](val value: FF[F]) {
def convert(r: R): F[A]
}
implicit def providesFunctorForBar[A] =
new ProvidesFor[Bar[A],Foo,Functor,A](Functor[Foo]) {
override def convert(r: Bar[A]): Foo[A] = r
}
因此,隐含的 val 将为我们提供 Foo 的函子以及从 Bar 到 Foo 的转换。
现在我们可以像这样提供对 Functor.Ops 的隐式转换:
implicit class FunctorOps[R[_],F[_],A](target: R[A])(implicit tc: ProvidesFor[R[A],F,Functor,A])
extends Functor.Ops[F,A] {
override val self = tc.convert(target)
override val typeClassInstance = tc.value
override def map[B](f: A => B): F[B] = typeClassInstance.map(self)(f)
override def imap[B](f: A => B)(g: B => A): F[B] = map(f)
}
现在这可以按预期工作:
Bar(1).imap(_+2)(_+5)
我们也可以对 Map 做同样的事情:
implicit def providesFunctorForMap[A,B] =
new ProvidesFor[Map[A,B],Foo,Functor,B](Functor[Foo]) {
override def convert(r: Map[A,B]): Foo[B] = r
}
Map((_:Int) + 1,Bar(5)).map(_+2)
由于某些奇怪的原因,我在扩展 Functor.Ops 时必须实现 map 和 imap,即使这些方法不是抽象的。事实上,当我不实现它们时它编译得很好,但它在运行时失败并出现 AbstractMethodError。所以不知何故,编译器认为实现存在,但它们不存在。我怀疑他们正在使用某种字节码优化工具来删除这些实现。