解码带有标记类型的案例类 [英] Decoding Case Class w/ Tagged Type

查看:50
本文介绍了解码带有标记类型的案例类的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

给定:

鉴于 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`@ 导入 shapeless.tag导入 shapeless.tag@特质福定义特征 Foo@ 导入 io.circe._, io.circe.generic.semiauto._导入 io.circe._, io.circe.generic.semiauto._@import shapeless.tag.@@导入 shapeless.tag.@@@implicit def taggedTypeDecoder[A, B](implicit ev: Decoder[A]): Decoder[A @@ B] =ev.map(标签[B][A](_))定义函数 taggedTypeDecoder

给定一个 Foo:

@case class F(x: String @@Foo)定义类 F

我可以召唤一个Decoder[String @@Foo]:

@解码器[字符串@@Foo]res17:解码器[字符串@@ Foo] = io.circe.Decoder$$anon$21@16b32e49

但不是F:

@deriveDecoder[F]cmd18.sc:1: 找不到 io.circe.generic.decoding.DerivedDecoder[ammonite.$sess.cmd16.F] 类型的惰性隐式值val res18 = 派生解码器 [F]^编译失败

如何获得Decoder[F]?

解决方案

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

我有一个 PR 可以让您的示例编译 - milessabin/shapeless#797(我检查了 publishLocal)

基本上 Lazy 的问题在于它过于急切地扩展类型别名(A @@ BA 的类型别名,带有 Tagged[B]) 进而触发 Scala 错误 - scala/bug#10506

Scala 错误没有明确的解决方案.这是使类型推断复杂化的子类型与参数多态性问题的另一个化身.其要点是 Scala 必须同时执行子类型检查和类型推断.但是,当我们将诸如 AB 之类的类型变量放入诸如 A with Tagged[B] 之类的精炼类型中时(实际上 circe 最终会寻找a FieldType[K, A with Tagged[B]] 其中 FieldType 是另一个隐藏精炼类型的类型别名),必须单独检查每个组件的子类型.这意味着我们选择检查组件的顺序决定了如何约束类型变量 AB.在某些情况下,它们最终会受到过度约束或约束不足,无法正确推断.

Apropo,无形测试显示 解决方法,但我认为它不适用于 circe,因为它使用某种宏而不是进行普通类型类派生.

长话短说,您可以:

  1. 等待一个无形的(请upvote #797)和随后的circe发布
  2. 不使用标记类型 =/
  3. 尝试使用不同的编码而不使用精炼或结构类型 - 也许是 alexknvl/newtypes?(我没试过)

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]?

解决方案

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)

这篇关于解码带有标记类型的案例类的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆