为什么隐式解析失败?

问题描述

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

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]FOption[Seq[_]]

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...