Lifeless: Filter Inversion Not on HList

I am trying to write a combinator for the scodec library, which converts Codec[K] in to Codec[L] , where K is HList and L is the equivalent of HList with all Unit elements removed.

The decoding implementation can be performed by decoding K , and then filtering all the elements of Unit . Filtering Unit elements is directly supported by the formless use of filterNot , which makes this trivial to implement.

Coding is implemented by converting L to K , inserting () into the corresponding indexes, and then delegating to the original Codec[K] . However, I cannot complete the conversion L => K

 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 tried several different solutions with no luck. Is this possible with the formless?

+6
source share
1 answer

I see no way to do this without a special type, but this approach is not so bad:

 import shapeless._ trait ReUnit[L <: HList, K <: HList] { def apply(l: L): K } object ReUnit { implicit object hnilReUnit extends ReUnit[HNil, HNil] { def apply(l: HNil): HNil = HNil } implicit def hlistReUnit[H, L <: HList, K <: HList] (implicit ru: ReUnit[L, K]): ReUnit[H :: L, H :: K] = new ReUnit[H :: L, H :: K] { def apply(l: H :: L): H :: K = l.head :: ru(l.tail) } implicit def unitReUnit[L <: HList, K <: HList] (implicit ru: ReUnit[L, K]): ReUnit[L, Unit :: K] = new ReUnit[L, Unit :: K] { def apply(l: L): Unit :: K = () :: ru(l) } } def reUnit[L <: HList, K <: HList](l: L)(implicit ru: ReUnit[L, K]) = ru(l) 

And then:

 scala> type Input = Int :: String :: HNil defined type alias Input scala> type WithUnits = Int :: Unit :: String :: Unit :: Unit :: HNil defined type alias WithUnits scala> reUnit[Input, WithUnits](1 :: "foo" :: HNil) res0: WithUnits = 1 :: () :: foo :: () :: () :: HNil 

Or in your context:

 def dropUnits[K <: HList, L <: HList](codec: Codec[K])(implicit fn: FilterNot.Aux[K, Unit, L] ru: ReUnit[L, K] ): 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) = codec.encode(ru(xs)) } 

I did not try to compile this dropUnits , but it should work.

The trick above is simply to work on what you want inductively. The base register converts HNil to HNil . Then, if you know how to convert X to Y , you also know how to do two things: convert A :: X to A :: Y and convert X to Unit :: Y And that’s all you need!

+4
source

Source: https://habr.com/ru/post/974574/


All Articles