我正在尝试使用 scalaz 库对 scala 中的 monads 做一些事情,并且在使其与子类型很好地配合使用时遇到了一些麻烦。
我已经开始定义我自己的 monad。为了简单起见,让它成为一个身份单子:
import scalaz._
import Scalaz._
class Id[+A] (val value : A) { }
implicit object IdMonad extends Monad[Id] {
override def pure[A](a : => A) = new Id(a)
override def bind[A, B](a : Id[A], f : A => Id[B]) = f(a.value)
}
接下来,我用一些额外的功能对其进行了扩展:
class ExtendedId[A] (value : A, val printer : A => String) extends Id[A](value) { }
有了这个附加功能,ExtendedId
不再是 monad。
现在我想将类型的对象ExtendedId[A]
用作Id[A]
:
def increment1(v : ExtendedId[Int]) : Id[Int] = {
for(v <- v) yield v + 1;
// ^
// error: could not find implicit value for parameter t: scalaz.Functor[test.package.ExtendedId]
}
请注意,我知道由于ExtendedId
不是 monad,所以我能得到的最好的输出是Id[Int]
,我可以接受!但不幸的是,该代码仍然无法编译。
但是,这个确实:
def asId[A](a : ExtendedId[A]) : Id[A] = a
def increment2(v : ExtendedId[Int]) {
for(v <- asId(v)) yield v + 1;
}
在这里,asId
函数只是将其参数向上转换为 from ExtendedId[A]
to Id[A]
。似乎它应该是完全多余的,但事实并非如此。
为什么会这样?确实存在从Id[A]
到包含的对象的隐式转换,map
并且显然确实存在从ExtendedId[A]
到的微不足道的隐式转换Id[A]
。那么,为什么编译器无法组合它们呢?