Неявное разрешение параметров для типов с более высоким родом - PullRequest
9 голосов
/ 28 сентября 2010

Рассмотрим следующий код:

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]). Есть ли способ избежать явной типизации, чтобы я получал неявный объект OptionBar в тесте, даже если я передаю тест с Some или None?

[Разъяснение]

  • Я использовал здесь в качестве примера Option, он также должен работать, если у меня есть Bar для абстрактного класса и т. Д.
  • Решение также должно работать, когда другие, не связанные бары находятся в области действия, скажем implicit object listBar extends Bar[list]

[Update]

Кажется, что создание параметра Бара контравариантным делает свое дело:

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

Но, конечно, это серьезное ограничение возможностей в Баре, поэтому я все еще надеюсь на лучший ответ.

Ответы [ 2 ]

7 голосов
/ 29 сентября 2010

Это не будет работать во всех случаях, но, как уже говорилось, вы можете попробовать это:

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]) = ()

Чтобы узнать больше о <:<, см.

5 голосов
/ 29 сентября 2010

Это потому, что 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))
    }
}
...