定义第三方类型类的实例,未找到隐式但显式工作正常
Defining instances of a third-party typeclass, implicit not found but explicit works fine
我正在使用 Slick's GetResult
typeclass 并希望使用 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
?我能做些什么来帮助它?
问题是 slick.jdbc.GetResult
是协变的。如果它是不变的,类型将被正确推断并且隐式将被解析。
解决方法是使用自定义不变类型别名 GetResult
隐藏协变 slick.jdbc.GetResult
。删除导入 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
Implicit resolution with covariance
我正在使用 Slick's GetResult
typeclass 并希望使用 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
?我能做些什么来帮助它?
问题是 slick.jdbc.GetResult
是协变的。如果它是不变的,类型将被正确推断并且隐式将被解析。
解决方法是使用自定义不变类型别名 GetResult
隐藏协变 slick.jdbc.GetResult
。删除导入 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
Implicit resolution with covariance