我很难理解为什么隐式解析在下面的情况下不起作用。希望你对这个问题有一些见解。
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
?
#########
也许我可以用不同的来克服上面的困难。下面的代码,但我仍然想知道为什么合成不工作。
因此,我们可以删除'compose ',并显式声明一个新的隐式转换,如下所示:
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
,如果你不创建类型别名编译器假设F
是Option[_]
和Seq[AddressPerson]
,这就是为什么隐式转换不起作用,因为代码在转换后不编译。
另一方面,当您使用类型别名时,编译器会清楚地知道F
是Option[Seq[_]]
,A
是AddressPerson