如何防止Scala满足这个隐式的';s参数本身,即使它';那是另一种类型?

如何防止Scala满足这个隐式的';s参数本身,即使它';那是另一种类型?,scala,shapeless,Scala,Shapeless,我正在尝试制作一个通用解码器,它根据字段上声明的shapeless.Tags对字段进行不同的解码。为此,我有一个隐式定义,如下所示,它可以将B的任何解码器转换为B@@Id的解码器(a是输入类型) 当我运行一个测试,并使用由此产生的解码器时,我得到一个堆栈溢出错误,表明Scala使用生成的解码器满足dec参数!如果我不使用惰性,那就不会发生,但我会得到“发散隐式扩展” 所以,我修改了代码,只是为了确保这是正在发生的事情。现在,我的定义是这样的 implicit def idTagDecoder

我正在尝试制作一个通用解码器,它根据字段上声明的
shapeless.Tag
s对字段进行不同的解码。为此,我有一个隐式定义,如下所示,它可以将
B
的任何解码器转换为
B@@Id
的解码器(
a
是输入类型)

当我运行一个测试,并使用由此产生的
解码器
时,我得到一个
堆栈溢出错误
,表明Scala使用生成的解码器满足
dec
参数!如果我不使用惰性,那就不会发生,但我会得到“发散隐式扩展”

所以,我修改了代码,只是为了确保这是正在发生的事情。现在,我的定义是这样的

  implicit def idTagDecoder[A, B](implicit dec: Lazy[Decoder[A, B]]): Decoder[A, B @@ Id] =
    new Decoder[A, B @@ Id] {
      override def decode(a: A): DecodeResult[B @@ Id] = {
        // These are different types, so the compiler shouldn't try to satisfy `dec` with `this`, but it does!
        require(dec.value != this)
        dec.value.decode(a).map(tag[Id](_))
      }
    }
正如预期的那样,这在运行时给了我一个“requirementfailed”

编译器比这更清楚。如果我尝试显式地执行它正在执行的操作来生成一个
解码器[JAny,UUID@@Id]
,它就会知道它的类型错误,并且无法编译

val d: Decoder[JAny, UUID @@ Id] = Id.idTagDecoder(Lazy(Id.idTagDecoder(Decoder.uuidDecoder)))
这是不是某种程度上的预期行为?如果是这样,我应该如何做我正试图做的事情?如果没有,有人知道如何解决这个问题吗

我试图用一个小例子来说明这个问题,但没有用。它在任何比我的用例更简单的事情上都能正常工作。您可以查看代码并运行失败的测试(使用
sbt测试

我使用的是shapeless 2.3.3和scala 2.12.13

谢谢



更新:鉴于这看起来像是Scala编译器中的一个bug,我继续使用Scala 2.13.5对其进行了测试,问题仍然存在。

这不是bug。有一个从T到Lazy[T]的隐式转换,导致您的方法解析隐式无限递归,因此StackOverflowError@texasbruce我明白,但它们不是同一类型的。这更像是将
A
转换为
Lazy[B]
。更准确地说,它将
解码器[JAny,UUID@@Id]
转换为
惰性[解码器[JAny,UUID]]
a@@B
只是继承
a
标记[B]
的类型
UUID@@Id
UUID
的子类。当它在隐式中解析时,它是一个有效的候选对象。那么,如果我尝试显式地执行相同的操作,为什么Scala会拒绝编译它?实际上,它对我来说很好:如果你不向方法提供类型参数,它将失败,因为它无法解析任何内容。
val d: Decoder[JAny, UUID @@ Id] = Id.idTagDecoder(Lazy(Id.idTagDecoder(Decoder.uuidDecoder)))