scala - 解码无形标记类型

标签 scala shapeless circe

鉴于菊石的以下情况:

@ 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 =:= StringB =:= Foo 。然而Scala会首先比较A <:< StringA <:< Tagged[Foo]结论是A <:< Tagged[Foo] with String (是的,相反)剩下 Nothing对于 B 。但是等等,我们需要一个隐式的 Decoder[A] ! - 这让我们陷入了循环。所以A受到过度约束并且 B受到约束不足。

编辑:如果我们制作@@,它似乎可以工作。抽象以防止编译器消除锯齿: milessabin/shapeless#807 。但现在它出问题了,我无法使数组工作。

关于scala - 解码无形标记类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48174650/

相关文章:

scala - Scala Future 的优雅处理[任一]]

scala - 如何检测当前项目是否是 sbt 动态任务内部的根项目?

scala - 如何避免在循环中分配的 var

scala - Shapeless - 将一个案例类转换为另一个具有不同顺序字段的案例类

scala - 从案例类中过滤出一个字段

list - Scala 中的异构列表;使用 map 功能

json - 如何配置 Circe 以停止使用嵌套类名作为编码 JSON 中的键名?

scala - scalaz.Maybe 的 Circe 解码器

scala - 在 Scala IDE 中使用 Akka

json - 使用 Scala 中的列表解析递归 JSON 结构