我想从一元案例类派生类型类的实例。但是,当我尝试隐式派生它时,我总是收到错误消息。如果我使用隐式方法显式导出它-它可以工作。我不确定,但是可能的原因是我错过了函数中的一些隐式类型
import shapeless._
import scala.reflect.ClassTag
import scala.reflect.runtime.universe.TypeTag
sealed trait Foo[A] {
def hello(): Unit
}
object Foo {
def apply[A](implicit foo: Foo[A]): foo.type = foo
def instance[A](implicit tag: ClassTag[A]): Foo[A] = new Foo[A] {
override def hello(): Unit = println(s"Hello from ${tag.runtimeClass.getName}")
}
}
trait Instances extends LowestPriority {
implicit val intHelloInstance: Foo[Int] = Foo.instance[Int]
}
trait LowestPriority {
implicit def derive[A: TypeTag, L <: HList, H](
implicit gen: Generic.Aux[A, L],
H: Lazy[Foo[H]],
isUnary: (H :: HNil) =:= L
): Foo[A] =
new Foo[A] {
override def hello(): Unit = {
print(s"Derived: ")
H.value.hello()
}
}
}
object T extends Instances {
case class A(a: Int)
def main(args: Array[String]): Unit = {
intHelloInstance.hello()
// val a: Foo[A] = derive[A, Int :: HNil, Int] // this works
// a.hello()
Foo[A].hello() // error
}
}
来自日志:
信息:(45,8)shapeless.this.Generic.materialize不是有效的shapeless.Generic.Aux [H,L]的隐式值,因为:hasMatchingSymbol报告错误:H不是case类,case类的,密封的特征或单位Foo [A] .hello()
我该如何解决?
这是行为取决于...要解析的隐式的顺序的情况之一。
如果您将签名修改为:
implicit def derive[A, L <: HList, H](
implicit gen: Generic.Aux[A, L],
isUnary: (H :: HNil) =:= L, // swapped
H: Lazy[Foo[H]] // with this
): Foo[A] = ...
编译器将:
HList
配对的L
A
L
等于确定过程中的H :: HNil
的某个H
H
来获取Lazy[Foo[H]]
并且您将成功编译Foo[A].hello()
。
当最后两个参数交换为问题中的内容时,编译器必须
H
(在我们的测试用例中,很可能WON“ T为Int)L
以使其匹配Generic
,现在它被迫证明A
可以由某些H :: HNil
表示,其中H
很可能不是Int
且无法执行,但是带有错误的错误信息]]这是这些情况之一,表明基于无形的推导有时是棘手的,并且在这里也表明,无形的作者在宏中假设,宏扩展失败的最可能原因是A
不是案例类,而我们只是看到可能也是编译器强加了一些不可能的证明,因为类型推断由于我们以错误的顺序解决了它们而使事情出错。