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
dropUnitsbut it should work.The trick above is just to work toward the instance you want inductively. The base case is converting an
HNilto anHNil. Then if you know how to convert anXto aY, you also know how to do two things: convert anA :: Xto anA :: Yand convert anXto aUnit :: Y. And that's all you need!