I am trying to do something with monads in scala using scalaz library, and have some trouble making it work nicely with subtyping.
I have started with defining my own monad. Let it be an identity monad for the sake of simplicity:
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)
}
Next, I have extended it with some additional functionality:
class ExtendedId[A] (value : A, val printer : A => String) extends Id[A](value) { }
With this additional functionality, ExtendedId
is not a monad anymore.
Now I want to use the object of type ExtendedId[A]
as an 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]
}
Note that I understand that since ExtendedId
is not a monad, the best I can get as an output is Id[Int]
, and I am okay with that! But unfortunately, that code still does not compile.
However, this one does:
def asId[A](a : ExtendedId[A]) : Id[A] = a
def increment2(v : ExtendedId[Int]) {
for(v <- asId(v)) yield v + 1;
}
Here, asId
function does nothing more than upcasting its argument to from ExtendedId[A]
to Id[A]
. It seems that it should be completely redundant, but it is not.
Why is this happening? There does exist an implicit conversion from Id[A]
to an object containing map
and there obviously does exist a trivial implicit conversion from ExtendedId[A]
to Id[A]
. So, why is the compiler unable combine them?