我怎样才能阻止 Scala 用它自己来满足这个隐式的参数,即使它是一个不同的类型?

问题描述

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

  implicit def idTagDecoder[A,B](implicit dec: Lazy[Decoder[A,B]]): Decoder[A,B @@ Id] =
    dec.value.decode(a).map(tag[Id](_))

当我运行测试并使用由此生成Decoder 时,我得到一个 StackOverflowError,表明 Scala 使用生成的解码器满足 dec 参数!如果我不使用 Lazy,则不会发生这种情况,但我会得到“发散的隐式扩展”。

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

  implicit def idTagDecoder[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](_))
      }
    }

正如预期的那样,这在运行时给了我一个“需求失败”。

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

val d: Decoder[JAny,UUID @@ Id] = Id.idTagDecoder(Lazy(Id.idTagDecoder(Decoder.uuidDecoder)))

这在某种程度上是预期的行为吗?如果是这样,我应该如何做我想做的事?如果没有,有人知道如何解决这个问题吗?

我试图得到一个演示这个问题的小例子无济于事。它的工作原理就像我期望的任何比我的用例更简单的东西。您可以查看代码并运行失败的测试 here(使用 sbt test)。

我使用的是 shapeless 2.3.3 和 Scala 2.12.13。

谢谢!


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

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)