Consider the following code:
object foo {
trait开发者_如何转开发 Bar[Q[_]]
implicit object OptionBar extends Bar[Option]
def test[T, C[_]](c: C[T])(implicit bar: Bar[C]) = ()
def main(args: Array[String]) {
test(Some(42): Option[Int]) //???
}
}
This works, but I need to type the Some(42) as Option[Int], else the implicit object OptionBar won't be resolved (because a Bar[Some] is expected instead). Is there a way to avoid the explicit typing, so that I get the implicit OptionBar object in test even if I feed test with a Some or None?
[Clarification]
- I used Option here just as example, it should also work if I have a
Bar
for an abstract class etc. - The solution should also work when other, unrelated Bars are in scope, say
implicit object listBar extends Bar[list]
[Update]
It seems that making Bar's parameter contravariant does the trick:
object foo {
trait Bar[-Q[_]] //<---------------
implicit object OptionBar extends Bar[Option]
implicit object ListBar extends Bar[List]
def test[T, C[_]](c: C[T])(implicit bar: Bar[C]) = ()
def main(args:Array[String]) {
test(Some(42))
}
}
But of course this is a severe limitation of the possibilities in Bar, so I still hope for a better answer.
It's not going to work in all cases, but as stated, you can try this:
object foo {
trait Bar[Q[_]]
implicit object OptionBar extends Bar[Option]
def test[T, C[_], D](c: D)(implicit bar: Bar[C], ev: D <:< C[T]) = ()
def main(args: Array[String]) {
test(Some(42)) //???
}
}
Interestingly, this doesn't infer, although it expresses the same thing:
def test[T, C[_], D <: C[T]](c: D)(implicit bar: Bar[C]) = ()
To learn more about <:<
, see:
- What do <:<, <%<, and =:= mean in Scala 2.8, and where are they documented?
- <:< operator in scala
That's because Some(42)
is a more specific type than Option[Int]
. It is a Some[Int]
. See alternative coding below:
object foo {
trait Bar[Q[_]]
implicit object OptionBar extends Bar[Option]
def test[T, C[_]](c: C[T])(implicit bar: Bar[C]) = ()
def main(args: Array[String]) {
test(Option(42))
}
}
精彩评论