Given a typeclass where instance selection should be performed based on the return type:
case class Monoid[A](m0: A) // We only care about the zero here
implicit def s[T] : Monoid[Set[T]] = Monoid(Set.empty[T])
implicit def l[T] : Monoid[List[T]] = Monoid(List.empty[T])
def mzero[A](implicit m: Monoid[A]) : A = m.m0
why does Scala (2.11.6) fail to resolve the proper instance:
scala> mzero : List[Int]
<console>:24: error: ambiguous implicit values:
both method s of type [T]=> Monoid[Set[T]]
and method l of type [T]=> Monoid[List[T]]
match expected type Monoid[A]
mzero : List[Int]
^
when it has no problems finding an implicit based on the return type when using the implicitly function (we redefine it here as i to illustrate how similar it is to mzero)
def i[A](implicit a : A) : A = a
scala> i : Monoid[List[Int]]
res18: Monoid[List[Int]] = Monoid(List())
The Monoid[A], instead of Monoid[List[Int]] in the error message is puzzling.
I would assume many scalaz contributors to be familiar with this problem as it seems to limit the convenience of typeclasses in scala.
EDIT: I'm looking into getting this working without forgoing type inference. Otherwise I'd like understand why that's not possible. If this limitation is documented as a Scala issue, I could not find it.
mzero[List[Int]].mzeroasdef mzero[A](implicit m: Monoid[_<:A]) : A = m.m0. Ut I'd personnaly go withmzero[List[Int]]as Travis Brown mentioned.Monoidcovariant, which indeed makes the code compile. As you probably cannot make it covariant (given that a complete definition ofMonoidwould have occurences ofAin contravariant position), the next best thing is to try to emulate this onmzeroalone by using an existential type, givingdef mzero[A](implicit m: Monoid[_<:A]). I would definitely be interested in getting an explanation of this oddness myself.