Класс случая декодирования с тегированным типом

Данный:

Учитывая следующее об Аммоните:

@ 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

Учитывая Foo:

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

Я могу вызвать Decoder[String @@ Foo]:

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

Но не 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

Как я могу получить Decoder[F]?


person Kevin Meredith    schedule 09.01.2018    source источник


Ответы (1)


Это ошибка в shapeless Lazy – milessabin/shapeless#309.

У меня есть PR, который компилирует ваш пример — milessabin/shapeless#797 (я проверил с publishLocal)

По сути, проблема в Lazy заключается в том, что он слишком рьяно расширяет псевдонимы типов (A @@ B — это псевдоним типа для A with Tagged[B]), что, в свою очередь, вызывает ошибку Scala — скала/ошибка#10506

Ошибка Scala не имеет четкого решения. Это еще одно воплощение проблемы подтипов и параметрического полиморфизма, которая усложняет вывод типов. Суть в том, что Scala должна выполнять проверку подтипов и вывод типов одновременно. Но когда мы помещаем некоторые переменные типа, такие как A и B, в уточненный тип, такой как A with Tagged[B] (на самом деле circe ищет FieldType[K, A with Tagged[B]], где FieldType — еще один псевдоним типа, скрывающий уточненный тип), подтип должен проверяться для каждого компонента отдельно. Это означает, что порядок, в котором мы выбираем проверку компонентов, определяет, как будут ограничены переменные типа A и B. В некоторых случаях они оказываются чрезмерно или недостаточно ограниченными и не могут быть правильно выведены.

Кстати, бесформенные тесты показывают обходной путь, но я не думаю, что он применим к circe, потому что он использует какой-то макрос, а не делает деривацию ванильного класса типов.

Короче говоря, вы можете:

  1. Дождитесь бесформенного (пожалуйста, проголосуйте за #797) и последующего циркового релиза.
  2. Не использовать тегированные типы =/
  3. Попробуйте использовать другую кодировку без уточненных или структурных типов — может быть, alexknvl/newtypes? (я не пробовал)
person g.krastev    schedule 12.01.2018