简体   繁体   中英

Why is implicit resolution failing?

I am having some difficulty understanding why implicit resolution is not working in the case below. Hopefully you will have some insights on the problem.

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

Does anyone know what is going on here? Why is implicit resolution not being able to understand that we can convert Option[Seq[Y]] to Y ?

#########

Maybe it is relevant to say that I can overcome the difficulty above with the different code below, but I still want to know why the composition does not work.

So, alternatively, we can delete 'composed' and instead declare a new implicit conversion explicitly like so:

implicit def composedImplicitConversion[F[_]: Jumper, G[_]: Jumper, A](value: F[G[A]]): A =
  implicitly[Jumper[G]].jump(implicitly[Jumper[F]].jump(value))

And now it works:

val addressPersonSeqOpt: Option[Seq[AddressPerson]] = ???
addressPersonSeqOpt.city  // it works!

Lastly, before I get hate for using implicit conversions like this, consider this an hypothetical question of sorts. I do not intent to be able to ever call addressPersonOpt.city at run-time, If you must know. this it to be used in tandem with a macro, I just need this implicit conversions to work. so that I can pass an adequate function signature and analyse it (the Tree corresponding to the function) with the macro only..

You need to give the hint to the compiler to figure out what is A and what is F , if you don't create the type alias the compiler asumes F is Option[_] and A Seq[AddressPerson] , that's why the implicit conversion doesn't work, because the code doesn't compile after the conversion.

On the other hand, when you use the type alias it is clear to the compiler that F is Option[Seq[_]] and A is AddressPerson

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM