展平任意嵌套的编解码器?
Flatten an arbitrarily nested codec?
作为 SCodec 的新用户,学习曲线相当曲折。尽管阅读了源代码和文档,我还是遇到了一个似乎无法解决的问题。
我希望能够将流行的编解码器定义为这样的函数
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]
但是,这样说是行不通的
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.
然而,当我 "inline" packedByte
时,喜欢
def packetInline : Codec[MyPacket] = (bool :: uint(4) :: uint(2) :: uint(2) :: bool).as[MyPacket]
一切都按预期编译和工作。我的直觉告诉我编解码器必须是 "flattened"(基于错误消息中的两个 HNils),但我一直无法展平编解码器本身或内部 HList 表示。
通过思考在类似情况下如何使用普通 value-level 列表来开始推理 hlist 通常很有用。例如,假设我们有一个值和一个列表:
val x = 0
val xs = List(1, 2, 3)
并且我们想创建一个新列表,在 xs
之前和之后都包含 x
。我们可以使用 +:
和 :+
:
scala> x +: xs :+ x
res0: List[Int] = List(0, 1, 2, 3, 0)
或:
scala> x :: (xs :+ x)
res1: List[Int] = List(0, 1, 2, 3, 0)
对于编解码器,没有 +:
运算符,但有 ::
和 :+
,您可以像使用列表版本一样使用它们价值水平:
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]
可以构造一个嵌套的 hlist,然后将其展平,但 :+
更为惯用。
作为 SCodec 的新用户,学习曲线相当曲折。尽管阅读了源代码和文档,我还是遇到了一个似乎无法解决的问题。
我希望能够将流行的编解码器定义为这样的函数
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]
但是,这样说是行不通的
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.
然而,当我 "inline" packedByte
时,喜欢
def packetInline : Codec[MyPacket] = (bool :: uint(4) :: uint(2) :: uint(2) :: bool).as[MyPacket]
一切都按预期编译和工作。我的直觉告诉我编解码器必须是 "flattened"(基于错误消息中的两个 HNils),但我一直无法展平编解码器本身或内部 HList 表示。
通过思考在类似情况下如何使用普通 value-level 列表来开始推理 hlist 通常很有用。例如,假设我们有一个值和一个列表:
val x = 0
val xs = List(1, 2, 3)
并且我们想创建一个新列表,在 xs
之前和之后都包含 x
。我们可以使用 +:
和 :+
:
scala> x +: xs :+ x
res0: List[Int] = List(0, 1, 2, 3, 0)
或:
scala> x :: (xs :+ x)
res1: List[Int] = List(0, 1, 2, 3, 0)
对于编解码器,没有 +:
运算符,但有 ::
和 :+
,您可以像使用列表版本一样使用它们价值水平:
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]
可以构造一个嵌套的 hlist,然后将其展平,但 :+
更为惯用。