问题描述
我很难理解为什么隐式解析在下面的情况下不起作用。希望您对这个问题有一些见解。
trait Jumper[F[_]] {
def jump[A](a: F[A]): A
}
implicit def conversion[F[_]: Jumper,A](a: F[A]): A = implicitly[Jumper[F]].jump(a)
implicit val optionJumps: Jumper[Option] = new Jumper[Option] {
override def jump[A](a: Option[A]): A = a.get
}
implicit val sequenceJumps: Jumper[Seq] = new Jumper[Seq] {
override def jump[A](a: Seq[A]): A = a.head
}
// What I would hope would enable chaining effects (i.e. composing Jumpers)
implicit def composed[F[_]: Jumper,G[_]: Jumper]: Jumper[({ type f[x] = F[G[x]] })#f] =
new Jumper[({ type f[x] = F[G[x]] })#f] {
override def jump[A](a: F[G[A]]): A = implicitly[Jumper[G]].jump(implicitly[Jumper[F]].jump(a))
}
case class Addressperson(city: String,road: String,number: Int,country: String)
val addressperson: Addressperson = ???
addressperson.city // obvIoUsly works,no implicit conversion occurs
val addresspersonopt: Option[Addressperson] = ???
addresspersonopt.city // works thanks to the implicit conversion and optionJumps
val addresspersonSeq: Seq[Addressperson] = ???
addresspersonSeq.city // works thanks to the implicit conversion and sequenceJumps
val addresspersonSeqOpt: Option[Seq[Addressperson]] = ???
addresspersonSeqOpt.city // does not work! I wanted this to work out of the Box via `composed`
// error is: value city is not a member of Option[Seq[Addressperson]]
// addresspersonSeqOpt.city
// ^
// however,if I define type alias
type Alias[Y] = Option[Seq[Y]]
val addresspersonSeqOpt: Alias[Addressperson] = ???
addresspersonSeqOpt.city // works
有人知道这是怎么回事吗?为什么隐式解析无法理解我们可以将 Option[Seq[Y]]
转换为 Y
?
#########
也许说我可以用下面的不同代码克服上面的困难是相关的,但我仍然想知道为什么组合不起作用。
所以,或者,我们可以删除 'composed',而是像这样显式声明一个新的隐式转换:
implicit def composedImplicitConversion[F[_]: Jumper,G[_]: Jumper,A](value: F[G[A]]): A =
implicitly[Jumper[G]].jump(implicitly[Jumper[F]].jump(value))
现在它可以工作了:
val addresspersonSeqOpt: Option[Seq[Addressperson]] = ???
addresspersonSeqOpt.city // it works!
最后,在我讨厌使用这样的隐式转换之前,请考虑这是一个假设性的问题。
我不打算在运行时调用 addresspersonopt.city
!
如果您必须知道,这将与宏一起使用。
我只需要这种隐式转换即可工作,以便我可以传递足够的函数签名并仅使用宏对其进行分析(与函数对应的树)..
解决方法
如果您不创建编译器假定的类型别名 A
是 {F
{1}} 和 A F
,这就是隐式转换不起作用的原因,因为代码在转换后无法编译。
另一方面,当您使用类型别名时,编译器很清楚 Option[_]
是 Seq[AddressPerson]
而 F
是 Option[Seq[_]]