Using a Filter in a Shapeless, Scala

It is easy to filter HList in formless type:

 val hlist = 1 :: 2 :: "3" :: true :: false :: HNil hlist.filter[Int] 

But how can I make my custom type filter? I want something like this: for example, I got a list of some functions:

 def function1(s: String) = s.toInt def function2(s: String) = s.toDouble def function3(i: Int) = i.toDouble val hflist = function1 _ :: function3 _ :: function2 _ :: HNil hflist customFilter[String] //> function1 _ :: function2 _ :: HNil 

So, after using this filter, a list of functions from the type String to some other type will be created.

I had an idea to use a card for this, but it was unsuccessful.

EDITION

Additional information about my comment:

I tried to test these ideas on a map:

So, if I have several lists (let's work with HList and hflist ):

 object allFunction extends Poly1 { implicit def default[T, M] = at[T => M](t => { object grabStringFunc extends skip { implicit def stringFunc[A] = at[T => A](_ :: HNil) } println(hflist flatMap grabStringFunc) //> here we should see result, list of functions }) hlist map allFunction //> result of this should be smth like (types) //> shapeless.::[Int => Double,shapeless.HNil]] //> shapeless.::[Int => Double,shapeless.HNil]] //> shapeless.::[String => Int,shapeless.::[String => Double,shapeless.HNil]] //> shapeless.HNil //> shapeless.HNil 

It is very interesting why it compiles and does not work correctly. In my opinion, this does not work, because the object cannot take prameters in this way ...

+6
source share
1 answer

The easiest way is to use a fold. First we need a polymorphic function that will add each element to the battery if it is of the desired type ( String => A for some A ) and ignores it otherwise:

 trait ignore extends Poly2 { implicit def default[A, L <: HList] = at[A, L]((_, l) => l) } object keepStringFunc extends ignore { implicit def stringFunc[A, L <: HList] = at[String => A, L](_ :: _) } 

Now the following will give the result that you want in both versions 1.2.4 and 2.0.0-M1:

 val filtered = hflist.foldRight(HNil)(keepStringFunc) 

You can also write your own class type in the Filter , FilterAux (or Filter.Aux ) model, etc. - and it will be a good exercise if you are trying to find Shapeless-but foldRight much easier.


Update: actually, what it costs for is a slightly more concise way to do this with flatMap :

 trait skip extends Poly1 { implicit def default[A] = at[A](_ => HNil) } object grabStringFunc extends skip { implicit def stringFunc[A] = at[String => A](_ :: HNil) } val filtered = hflist flatMap grabStringFunc 

I personally find the foldRight version more obvious, but this one is pretty elegant too.


In response to your comment: you can make the solution more like the following:

 trait skip extends Poly1 { implicit def default[A] = at[A](_ => HNil) } trait grabFuncFrom[T] extends skip { implicit def stringFunc[A] = at[T => A](_ :: HNil) } object grabStringFunc extends grabFuncFrom[String] val filtered = hflist flatMap grabStringFunc 

But you still need the last step, in which you create a function of a higher rank as an object (see, for example, this answer , and Miles will comment on this to discuss this issue).

+13
source

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


All Articles