Poly2 Common Groove for Shapeless Hlist

I am trying to convert the next hlist

Some(C(15)) :: None :: Some(B(55)) :: None :: Some(A(195)) :: HNil 

to

 C(15) :: B(55) :: A(195) :: HNil 

Here is what I have at the moment:

  import shapeless._ case class A(value: Int) case class B(value: Int) case class C(value: Int) trait folderLP extends Poly2 { implicit def default[T, L <: HList] = at[T, L]((acc, t) => acc) } object folder extends folderLP { implicit def none[T, L <: HList] = at[None.type, L]((t, acc) => acc) implicit def someDiameter[T, L <: HList] = at[Some[C], L]((t, acc) => t.get :: acc) implicit def someRatio[T, L <: HList] = at[Some[B], L]((t, acc) => t.get :: acc) implicit def someWidth[T, L <: HList] = at[Some[A], L]((t, acc) => t.get :: acc) } val test = Some(C(15)) :: None :: Some(B(55)) :: None :: Some(A(195)) :: HNil val filtered = test.foldRight[HList](HNil)(folder) 

this works, but I would like to make it generic so that it works for any type wrapped in Some, without having to write each case

+5
source share
1 answer

First for a literal answer. Note that most parameters of type T not used. You can use this T to make your function match any element of type Some[T] :

 trait folderLP extends Poly2 { implicit def default[T, L <: HList] = at[T, L]((_, acc) => acc) } object folder extends folderLP { implicit def some[T, L <: HList] = at[Some[T], L]((t, acc) => t.get :: acc) } 

Note that you don't even need the none case if you switch the order of the arguments to default .

Also note that you probably want to use the following definition of filtered :

 val filtered = test.foldRight(HNil: HNil)(folder) 

This will have HNil statically injected as HNil instead of HList , which will be useful for almost everything you want to do along the line, for example try filtered.length on your original version and then on that.

You really don't need a fold for this operation, although -a flatMap will do:

 trait filterLP extends Poly1 { implicit def any[T] = at[T](_ => HNil) } object filter extends filterLP { implicit def some[T] = at[Some[T]](_.get :: HNil) } 

And then:

 val filtered = test.flatMap(filter) 

Finally, it is worth noting that this will only work on HList , where the elements none and Some statically typed as none and Some -a Some[A] , for example, statically typed as a Option[A] will be filtered. This makes it ridiculous (at least I don’t see any practical use), but in fact you can’t perform this type of level filter in any way if at compile time you don’t know whether Option will be empty or not.

+7
source

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


All Articles