Свести произвольно вложенный кодек?
Как новый пользователь 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]
Но это не работает, говоря
Не удалось доказать, что бесформенный.::[Boolean,shapeless.::[shapeless.::[Int,shapeless.::[Int,shapeless.::[Int,shapeless.HNil]]],shapeless.::[Boolean,shapeless.HNil]]] можно преобразовать в / из cmd504.MyPacket.
Тем не менее, когда я "встроенный" packedByte
, лайк
def packetInline : Codec[MyPacket] = (bool :: uint(4) :: uint(2) :: uint(2) :: bool).as[MyPacket]
Все компилируется и работает как положено. Моя интуиция подсказывает мне, что кодек должен быть "сплющен" (основываясь на двух HNils в сообщении об ошибке), но я не смог сгладить сам кодек или внутреннее представление HList.
1 ответ
Часто полезно начинать рассуждать о списках, думая о том, как вы будете работать с обычными списками уровня значений в аналогичной ситуации. Например, предположим, что у нас есть значение и список:
val x = 0
val xs = List(1, 2, 3)
И мы хотим создать новый список с x
как до, так и после xs
, Мы можем использовать +:
а также :+
:
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)
В случае 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]
Можно было бы создать вложенный список и затем сгладить его, но :+
гораздо идиоматичнее.