1

我在 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]]

导出这个隐式实例是完全可以的。

4

2 回答 2

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
于 2019-01-30T08:33:03.280 回答
1

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

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,则需要一遍又一遍地解决此问题,因此最好将其放在您的工具箱中。

于 2019-01-30T08:34:48.813 回答