I'm trying to write a combinator for the scodec library that converts a Codec[K]
in to a Codec[L]
where K
is an HList
and L
is the equivalent HList
with all Unit
elements removed.
Implementing decoding can be done by decoding a K
and then filtering out all Unit
elements. Filtering out Unit
elements is directly supported by shapeless using filterNot
, which makes this trivial to implement.
Implementing encoding is accomplished by converting an L
to a K
, inserting ()
at the appropriate indices, and then delegating to the original Codec[K]
. I'm having trouble implementing the L => K
conversion though.
def dropUnits[K <: HList, L <: HList](codec: Codec[K])(
implicit fltr: FilterNot.Aux[K, Unit, L]): Codec[L] = new Codec[L] {
override def decode(buffer: BitVector) =
codec.decode(buffer).map { case (rest, l) => (rest, l.filterNot[Unit]) }
override def encode(xs: L) = {
???
}
}
I've tried a few different solutions without luck. Is this possible with shapeless?
I don't see a way to do this without a custom type class, but that approach isn't too bad:
And then:
Or in your context:
I didn't try compiling this
dropUnits
but it should work.The trick above is just to work toward the instance you want inductively. The base case is converting an
HNil
to anHNil
. Then if you know how to convert anX
to aY
, you also know how to do two things: convert anA :: X
to anA :: Y
and convert anX
to aUnit :: Y
. And that's all you need!