鉴于菊石的以下情况:
@ import $ivy.`io.circe::circe-core:0.9.0`
@ import $ivy.`io.circe::circe-generic:0.9.0`
@ import $ivy.`com.chuusai::shapeless:2.3.3`
@ import shapeless.tag
import shapeless.tag
@ trait Foo
defined trait Foo
@ import io.circe._, io.circe.generic.semiauto._
import io.circe._, io.circe.generic.semiauto._
@ import shapeless.tag.@@
import shapeless.tag.@@
然后,我尝试定义一个通用标记类型解码器:
@ implicit def taggedTypeDecoder[A, B](implicit ev: Decoder[A]): Decoder[A @@ B] =
ev.map(tag[B][A](_))
defined function taggedTypeDecoder
它在显式拼写出 String @@ Foo
时起作用:
@ val x: String @@ Foo = tag[Foo][String]("foo")
x: String @@ Foo = "foo"
@ implicitly[Decoder[String @@ Foo]]
res10: Decoder[String @@ Foo] = io.circe.Decoder$$anon$21@2b17bb37
但是,在定义类型别名时:
@ type FooTypeAlias = String @@ Foo
defined type FooTypeAlias
它没有编译:
@ implicitly[Decoder[FooTypeAlias]]
cmd12.sc:1: diverging implicit expansion for type io.circe.Decoder[ammonite.$sess.cmd11.FooTypeAlias]
starting with method decodeTraversable in object Decoder
val res12 = implicitly[Decoder[FooTypeAlias]]
^
Compilation Failed
这是为什么呢?有已知的“修复方法吗?”
最佳答案
你很幸运,在同一天遇到了两个编译器错误。这是scala/bug#8740 。好的?消息是 this comment 中有一个部分修复正在等待中。让某人站出来做公关(也许这就是你)。我相信它是部分的,因为它看起来适用于特定标签,但不适用于通用标签(我不是 100% 确定)。
你看到隐式展开发散的原因真的很有趣。编译器可以一步扩展所有别名(基本上从 FooTypeAlias |= String with Tagged[Foo]
开始),也可以不扩展任何内容。所以当它比较String @@ Foo
时和A @@ B
它不会扩展,因为它们按原样匹配。但当它比较FooTypeAlias
时和A @@ B
它完全扩展,并且最终处于一种必须比较精炼类型的情况,其中一个类型包含类型变量(请参阅我的 answer 到您的其他相关问题)。在这里,我们精心设计的抽象再次崩溃,约束的顺序开始变得重要。作为程序员的你,正在查看A with Tagged[B] <:< String with Tagged[Foo]
知道最好的匹配是 A =:= String
和B =:= Foo
。然而Scala会首先比较A <:< String
和A <:< Tagged[Foo]
结论是A <:< Tagged[Foo] with String
(是的,相反)剩下 Nothing
对于 B
。但是等等,我们需要一个隐式的 Decoder[A]
! - 这让我们陷入了循环。所以A
受到过度约束并且 B
受到约束不足。
编辑:如果我们制作@@
,它似乎可以工作。抽象以防止编译器消除锯齿: milessabin/shapeless#807 。但现在它出问题了,我无法使数组工作。
关于scala - 解码无形标记类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48174650/