Scala shapeless Generic.Aux implicit parameter not found in unapply

旧城冷巷雨未停 提交于 2020-01-05 06:26:46

问题


I encountered the following problem with implicits in Scala, using Shapeless's Generic.Aux:

  case class Complex(re: Double, im: Double)

  object Prod2 {
    def unapply[C, A, B](c: C)(implicit C: Generic.Aux[C, A :: B :: HNil]) = Some((C.to(c).head, C.to(c).tail.head))
  }

  val c = Complex(1.0, 2.0)
  val Prod2(re, im) = c

The code above does not compile. It reports

Error:(22, 7) could not find implicit value for parameter C: shapeless.Generic.Aux[nexus.ops.Test.Complex,A :: B :: shapeless.HNil]
  val Prod2(re, im) = c
Error:(22, 7) not enough arguments for method unapply: (implicit C: shapeless.Generic.Aux[nexus.ops.Test.Complex,A :: B :: shapeless.HNil])Some[(A, B)].
Unspecified value parameter C.
  val Prod2(re, im) = c

However, if I manually do

implicitly[Generic.Aux[Complex, Double :: Double :: HNil]]

it is perfectly OK to derive this implicit instance.


回答1:


The following code works:

import shapeless.ops.hlist.IsHCons
import shapeless.{::, Generic, HList, HNil}

case class Complex(re: Double, im: Double)

object Prod2 {
  def unapply[C, L <: HList, H, T <: HList, H1, T1 <: HList](c: C)(implicit
    C: Generic.Aux[C, L],
    isHCons: IsHCons.Aux[L, H, T],
    isHCons1: IsHCons.Aux[T, H1, T1]) = Some((C.to(c).head, C.to(c).tail.head))
}

val c = Complex(1.0, 2.0)
val Prod2(re, im) = c



回答2:


Unfortunately the compiler simply isn't smart enough to perform the unification that would be necessary to infer A and B here. You can read about some of the details of this problem in section 4.3 of Underscore's Type Astronaut’s Guide to Shapeless. The book provides a workaround using IsHCons, but in this case I think requiring a <:< proof is a little cleaner:

import shapeless.{::, Generic, HList, HNil}

case class Complex(re: Double, im: Double)

object Prod2 {
  def unapply[C, L <: HList, A, B](c: C)(implicit
    C: Generic.Aux[C, L],
    ev: L <:< (A :: B :: HNil)
  ) = Some((C.to(c).head, C.to(c).tail.head))
}

And then:

scala> val c = Complex(1.0, 2.0)
c: Complex = Complex(1.0,2.0)

scala> val Prod2(re, im) = c
re: Double = 1.0
im: Double = 2.0

It's disappointing, but this is a workaround you'll need over and over if you work with Shapeless, so it's good to have it in your toolbox.



来源:https://stackoverflow.com/questions/54432439/scala-shapeless-generic-aux-implicit-parameter-not-found-in-unapply

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!