无法使用无形导出类型类的隐式实例

问题描述 投票:1回答:1

我想从一元案例类派生类型类的实例。但是,当我尝试隐式派生它时,我总是收到错误消息。如果我使用隐式方法显式导出它-它可以工作。我不确定,但是可能的原因是我错过了函数中的一些隐式类型

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

我该如何解决?

scala shapeless
1个回答
1
投票

这是行为取决于...要解析的隐式的顺序的情况之一。

如果您将签名修改为:

  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不是案例类,而我们只是看到可能也是编译器强加了一些不可能的证明,因为类型推断由于我们以错误的顺序解决了它们而使事情出错。

© www.soinside.com 2019 - 2024. All rights reserved.