.hlist 编解码器上的 .dropUnit 似乎不起作用

.dropUnit on .hlist'ed codecs doesnt seem to work

对于 "big" 编解码器,当直接从 HLists 创建编解码器并应用 .dropUnits

时,Scala phase typer 需要永远(我们说的是分钟)
( ignore(6) ::
  uint(2) ::
  uint(30) ::
  int(4) ::
  int(8) ::
  uint(10) ::
  bool(1) ::
  int(28) ::
  int(27) ::
  uint(12) ::
  uint(9) ::
  uint(6) ::
  int(2) ::
  ignore(3) ::
  bool(1) ::
  uint(19)
).dropUnits.as[SomeBigCaseClass]

~ 创建编解码器,然后像这样应用 .hlist 似乎要快得多:

( ignore(6) ~
  uint(2) ~
  ...
).hlist.dropUnits.as[SomeBigCaseClass]

但这似乎行不通。

Could not prove that this.Out can be converted to/from reports.SomeBigCaseClass.
  ).hlist.dropUnits.as[SomeBigCaseClass]
                      ^

我找到的最简单的解决方案是省略 Unit 内联值。

( (ignore(6) dropLeft 
   uint(2)) :: 
  ...
).as[SomeBigCaseClass]

对于有很多忽略的编解码器,非常欢迎此功能。我究竟做错了什么?我是否完全忽略了 .hlist 的要点?

hlist 组合器将 Codec[A] 转换为 Codec[A :: HNil]。这通常与其他组合器一起使用,例如 flatZip,它需要基于 HList 的编解码器。

重复使用 ~ 运算符创建一个基于左关联 Tuple2 的结构。例如,int8 ~ bool ~ int8 的类型为 Codec[((Int, Boolean), Int)]。最新的 scodec 快照 1.7.0-SNAPSHOT(虽然不是 1.7.0-RC1)具有 flattenLeftPairs 方法,它将左关联元组编解码器转换为等效的 HList 编解码器。

scodec 的未来版本将有一个像 ~ 这样的组合器,但不是嵌套 Tuple2 个实例,而是创建 TupleN 个实例。例如:int8 ~~ bool ~~ int8 的类型为 Codec[(Int, Boolean, Int)]。虽然这还没有被整合。通过减少分配的元组数量,这既有性能优势,也有便利优势,因为它允许通过 widenOpt(SomeBigCaseClass.apply, SomeBigCaseClass.unapply).

绑定到 case 类

最后,观察到的 dropUnits 编译器性能问题确实是组合器定义方式的问题。这已在 scodec-core 1.7.0-SNAPSHOT 中修复(尽管不是 1.7.0-RC1)。参见 https://github.com/scodec/scodec/issues/41