Decoding Case Class w/ Tagged Type

假装没事ソ 提交于 2019-12-23 09:30:01

问题


Given:

Given the following on Ammonite:

@ 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

Given a Foo:

@ case class F(x: String @@ Foo)  
defined class F

I can summon an Decoder[String @@ Foo]:

@ Decoder[String @@ Foo] 
res17: Decoder[String @@ Foo] = io.circe.Decoder$$anon$21@16b32e49

But not a F:

@ deriveDecoder[F] 
cmd18.sc:1: could not find Lazy implicit value of type io.circe.generic.decoding.DerivedDecoder[ammonite.$sess.cmd16.F]
val res18 = deriveDecoder[F]
                         ^
Compilation Failed

How can I get a Decoder[F]?


回答1:


This is a bug in shapeless' Lazy - milessabin/shapeless#309

I have a PR that makes your example compile - milessabin/shapeless#797 (I checked with publishLocal)

Basically the problem in Lazy is that it expands type aliases too eagerly (A @@ B is a type alias for A with Tagged[B]) which in turn triggers a Scala bug - scala/bug#10506

The Scala bug doesn't have a clear solution in sight. It's another incarnation of the subtyping vs parametric polymorphism problem that complicates type inference. The gist of it is that Scala has to perform subtype checking and type inference at the same time. But when we put some type variables like A and B in a refined type like A with Tagged[B] (actually circe ends up looking for a FieldType[K, A with Tagged[B]] where FieldType is yet another type alias hiding a refined type), subtyping has to be checked for each component individually. This means that the order in which we choose to check the components determines how the type variables A and B will be constrained. In some cases they end up over- or under-constrained and cannot be inferred correctly.

Apropo, the shapeless tests show a workaround, but I don't think it applies to circe, because it's using some kind of macro rather than doing vanilla typeclass derivation.

Long story short you can:

  1. Wait for a shapeless (please upvote #797) and subsequent circe release
  2. Not use tagged types =/
  3. Try to use a different encoding without refined or structural types - maybe alexknvl/newtypes? (I haven't tried)


来源:https://stackoverflow.com/questions/48174799/decoding-case-class-w-tagged-type

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!