[英]Flatten an arbitrarily nested codec?
As a new user of SCodec, there is quite a learning curve. 作为SCodec的新用户,有一个相当的学习曲线。 I've hit a snag that I can't seem to solve despite reading the source and docs. 尽管阅读了源代码和文档,我还是遇到了一些似乎无法解决的问题。
I want to be able to define popular codecs as functions like this 我希望能够将流行的编解码器定义为这样的函数
def packedByte : Codec[Int :: Int :: Int :: HNil] = uint(4) :: uint(2) :: uint(2)
And then combine them in to higher level codecs like this which decode to and encode from case classes like this 然后将它们组合到更高级别的编解码器中,这样可以对像这样的case类进行解码和编码
case class MyPacket(foo : Boolean, first : Int, second : Int, third : Int, bar : Boolean)
def packet : Codec[MyPacket] = (bool :: packedByte :: bool).as[MyPacket]
But, this doesn't work saying 但是,这不起作用
Could not prove that shapeless.::[Boolean,shapeless.::[shapeless.::[Int,shapeless.::[Int,shapeless.::[Int,shapeless.HNil]]],shapeless.::[Boolean,shapeless.HNil]]] can be converted to/from cmd504.MyPacket. 无法证明自己没有形状。:[布尔,无形。:无形。:[Int,Shapeless。::] Int,Shapeless。:::Int ,shapeless .HNil]]],形状::[布尔,shapeless.HNil]]]可以转换为/从cmd504.MyPacket。
Yet, when I "inline" the packedByte
, like 然而,当我“内联” packedByte
,就像
def packetInline : Codec[MyPacket] = (bool :: uint(4) :: uint(2) :: uint(2) :: bool).as[MyPacket]
Everything compiles and works as expected. 一切都按预期编译和工作。 My intuition tells me that the Codec must be "flattened" (based off of the two HNils in the error message), but I have been unable to flatten the Codec itself or the internal HList representation. 我的直觉告诉我,编解码器必须“扁平化”(基于错误消息中的两个HNils),但我无法压缩编解码器本身或内部HList表示。
It's often useful to start reasoning about hlists by thinking about how you'd work with ordinary value-level lists in a similar situation. 通过考虑在类似情况下如何使用普通的价值级列表来开始推理hlists通常很有用。 For example, suppose we've got a value and a list: 例如,假设我们有一个值和一个列表:
val x = 0
val xs = List(1, 2, 3)
And we want to create a new list with x
both before and after xs
. 我们想在xs
之前和之后创建一个包含x
的新列表。 We can use +:
and :+
: 我们可以使用+:
和:+
:
scala> x +: xs :+ x
res0: List[Int] = List(0, 1, 2, 3, 0)
Or: 要么:
scala> x :: (xs :+ x)
res1: List[Int] = List(0, 1, 2, 3, 0)
In the case of Scodec, there's no +:
operator, but there are ::
and :+
, and you can use them exactly as you would use the list versions at the value level: 在Scodec的情况下,没有+:
运算符,但有::
和:+
,你可以完全像在值级别使用列表版本一样使用它们:
import scodec._, scodec.codecs._, shapeless._
def packedByte: Codec[Int :: Int :: Int :: HNil] =
uint(4) :: uint(2) :: uint(2)
case class MyPacket(
foo: Boolean,
first: Int,
second: Int,
third: Int,
bar: Boolean
)
def packet: Codec[MyPacket] = (bool :: (packedByte :+ bool)).as[MyPacket]
It would be possible to construct a nested hlist and then flatten it, but :+
is far more idiomatic. 有可能构建一个嵌套的hlist然后展平它,但是:+
更加惯用。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.