【问题标题】:Implicit parameter resolution for higher kinded types更高种类类型的隐式参数解析
【发布时间】: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


【解决方案1】:

并非在所有情况下都有效,但如前所述,您可以试试这个:

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)) //???
  }
}

有趣的是,这并没有推断,尽管它表达了同样的事情:

def test[T, C[_], D <: C[T]](c: D)(implicit bar: Bar[C]) = ()

要了解有关&lt;:&lt; 的更多信息,请参阅:

【讨论】:

  • 这可行,但是如果您在该范围内为 Bar 添加另一个隐式,例如 implicit object ListBar extends Bar[List],您会收到“模糊隐式值”错误。
  • 我对这个答案给予了赏金,因为它展示了一种很好的技术并解决了最初的问题,这个问题的表述不够精确。但是,我仍然希望得到提示如何解决“歧义隐含值”问题。
  • 好吧,三年后的几个版本的Scala,似乎没有答案存在。 (我也面临同样的挑战。)
【解决方案2】:

这是因为Some(42) 是比Option[Int] 更具体的类型。这是一个Some[Int]。请参阅下面的替代编码:

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))
    }
}

【讨论】:

  • 我真的不提倡使用Option.apply,除非用它来编码一个空检查。顺便说一句,对于 scalaz,我会写 42.some42.pure[Option],这两种类型都是 Option[Int]
  • @retronym - 你为什么不提倡使用Option.apply
  • 当我有一个可能为空的引用想要转换为SomeNone 时,我会使用它。我可以阅读Some(x) : Option[A] 并推断我将拥有Some 而无需追踪x 的来源。如果参数是字面量,如本例所示,也可以。
  • 我在这里使用 Option 只是一个例子。当我有抽象基类的“条”等时,我想避免显式输入。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-08-22
  • 1970-01-01
  • 2021-01-07
  • 2019-10-07
  • 1970-01-01
相关资源
最近更新 更多