为什么隐式解析失败?



我很难理解为什么隐式解析在下面的情况下不起作用。希望你对这个问题有一些见解。

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,如果你不创建类型别名编译器假设FOption[_]Seq[AddressPerson],这就是为什么隐式转换不起作用,因为代码在转换后不编译。

另一方面,当您使用类型别名时,编译器会清楚地知道FOption[Seq[_]],AAddressPerson

相关内容

  • 没有找到相关文章

最新更新