Определение экземпляров стороннего класса типов, неявное не найденное, но явное работает нормально - PullRequest
0 голосов
/ 04 октября 2018

Я работаю с классом типа GetResult Слика и хотел использовать Shapeless для получения экземпляров GetResult[Option[(A, B, C...)]]

Что я хочу:

Учитывая неявное GetResult[Option[A]], GetResult[Option[B]], ...,
неявно генерирует GetResult[Option[(A, B, ...)]]

Что я пробовал

trait CanGetOption[T] {
    def getOption: GetResult[Option[T]]
}
object CanGetOption {
    // convenience implicit resolver
    def apply[T](implicit canGetOption: CanGetOption[T]): CanGetOption[T] = canGetOption

    // base case: HNil
    implicit val getHNilOption: CanGetOption[HNil] = from(GetResult { _ => Some(HNil) })

    // recursion case: H :: Tail
    implicit def getHConsOption[H, Tail <: HList](
        implicit getHeadOption: GetResult[Option[H]], 
        canGetTailOption: CanGetOption[Tail]
    ): CanGetOption[H :: Tail] = from(GetResult[Option[H :: Tail]] { r =>
        val headOpt = getHeadOption(r)
        val tailOpt = canGetTailOption.getOption(r)
        for(head <- headOpt; tail <- tailOpt) yield head :: tail
    })

    // generic case: A, given a A <-> Repr conversion
    // I also tried moving this into a "LowPriorityImplicits" thing, just in case
    implicit def getGenericOption[A, Repr <: HList](
        implicit gen: Generic.Aux[A, Repr], 
        getReprOpt: CanGetOption[Repr]
    ): CanGetOption[A] = from(GetResult { r =>
        val reprOpt = getReprOpt.getOption(r)
        reprOpt.map(gen.from)
    })
}

implicit def resolveOptionGetter[T: CanGetOption]: GetResult[Option[T]] = 
    CanGetOption[T].getOption

Проблема:

Когда я импортировал вышеупомянутое, resolveOptionGetter, кажется, не учитывается при поиске имплицитов:

scala> implicitly[GetResult[Option[(Int, Int)]]]
<console>:19: error: could not find implicit value for parameter e: scala.slick.jdbc.GetResult[Option[(Int, Int)]]
       implicitly[GetResult[Option[(Int, Int)]]]
             ^

scala> resolveOptionGetter[(Int, Int)]
res1: scala.slick.jdbc.GetResult[Option[(Int, Int)]] = <function1>

Почему компилятор не может найти resolveOptionGetterв неявном поиске?Что я могу сделать, чтобы помочь ему?

1 Ответ

0 голосов
/ 05 октября 2018

Дело в том, что slick.jdbc.GetResult является ковариантным.Если бы он был инвариантным, типы были бы выведены правильно, и последствия были бы разрешены.

Обходной путь скрывает ковариант slick.jdbc.GetResult с пользовательским псевдонимом инвариантного типа GetResult.Удалите import slick.jdbc.GetResult и напишите в свой исходный файл

type GetResult[T] = slick.jdbc.GetResult[T]

object GetResult {
  def apply[T](implicit f: PositionedResult => T): GetResult[T] = slick.jdbc.GetResult.apply
}

Теперь implicitly[GetResult[Option[(Int, Int)]]] компилируется.Протестировано в Scala 2.12.7 + Shapeless 2.3.3 + Slick 3.2.3.

Дисперсия часто создает проблемы для неявного разрешения:

https://github.com/scala/bug/issues/10099

https://github.com/locationtech/geotrellis/issues/1292

Неявное разрешение с ковариацией

...