【问题标题】:Scala shapeless Generic.Aux implicit parameter not found in unapply在 unapply 中找不到 Scala 无形 Generic.Aux 隐式参数
【发布时间】:2019-06-23 06:04:07
【问题描述】:

我在 Scala 中使用 Shapeless 的 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

上面的代码无法编译。它报告

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

但是,如果我手动这样做

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

派生这个隐式实例是完全可以的。

【问题讨论】:

标签: scala shapeless unapply


【解决方案1】:

以下代码有效:

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

【讨论】:

  • 你领先了我一分钟,但我的回答提供了更多的背景信息,并且(在我看来)是一个更好的解决方案,所以我将保留它。
  • @TravisBrown 有趣的是,如果我们将Aux 删除为第二个IsHConsdef unapply[C, L &lt;: HList, H, T &lt;: HList](c: C)(implicit C: Generic.Aux[C, L], isHCons: IsHCons.Aux[L, H, T], isHCons1: IsHCons[T]): Option[(H, isHCons1.H)] = ...,那么我们将拥有error during expansion of this match (this is a scalac bug). The underlying error was: type mismatch; found : Double required: isHCons1.H
【解决方案2】:

不幸的是,编译器根本不够聪明,无法执行在此处推断AB 所需的统一。您可以在Underscore's Type Astronaut’s Guide to Shapeless 的第 4.3 节中阅读有关此问题的一些详细信息。这本书提供了一个使用IsHCons 的解决方法,但在这种情况下,我认为要求&lt;:&lt; 证明更简洁:

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))
}

然后:

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

令人失望,但如果您使用 Shapeless,则需要反复使用此解决方法,因此最好将其放入您的工具箱中。

【讨论】:

  • 非常感谢您的回答和指导!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-09-12
  • 1970-01-01
  • 1970-01-01
  • 2012-09-02
  • 2015-05-14
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多