【发布时间】:2011-04-18 11:48:08
【问题描述】:
考虑以下代码:
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]) //???
}
}
这可行,但我需要将 Some(42) 键入为 Option[Int],否则将无法解析隐式对象 OptionBar(因为需要使用 Bar[Some])。有没有办法避免显式键入,以便即使我使用 Some 或 None 提供测试,我也会在测试中获得隐式 OptionBar 对象?
[澄清]
- 我在这里使用 Option 作为示例,如果我有一个
Bar用于抽象类等,它也应该工作。 - 当其他不相关的条在范围内时,该解决方案也应该有效,例如
implicit object listBar extends Bar[list]
[更新]
似乎使 Bar 的参数逆变可以解决问题:
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))
}
}
但当然这是对 Bar 可能性的严重限制,所以我仍然希望得到更好的答案。
【问题讨论】:
-
为什么逆变是一个严重的限制?如果不使用它,那么 Bar 是不变的。如果您尝试使用 Bar 作为类型类来对抗更高类型的类型,那么我认为逆变似乎很合适。当然,直到你想以不同的方式对待子类。但是在这种情况下,您还有其他技巧,例如隐式解析“优先级”
-
@Josh:考虑类似
trait Bar[Q[_]] { def zero[T]:Q[T] },在我的示例中返回 None 和 Nil。但是,如果我将 Q 定义为逆变,我不能在 Bar 中使用这样的方法。当您知道如何解决此问题时,请告诉我... -
此外,对于自然逆变类型类,例如
Equal[T],隐式搜索将优先于Equal[Animal]而不是Equal[Dog]:scala-lang.org/node/4626。继承和类型类很难融合在一起。
标签: scala implicit higher-kinded-types