It is easy to filter HList
in shapeless by type:
val hlist = 1 :: 2 :: "3" :: true :: false :: HNil
hlist.filter[Int]
But how can I make my custom type filter? I want smth like that: for example I got 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 usage of this filter, list of functions from type String
to some other type will be constructed.
I had an idea to use map for this, but it was not successfull.
EDITION
More information about my comment:
I tried to test this ideas in map:
So if i got some lists (lets operate with hlist
& 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
Very interesting, why it compiles and works incorrect? As I think it is not works, cause object cant take type prameters in such a way...
The easiest way is to use a fold. First we need a polymorphic function that will add each item to the accumulator if it has the desired type (
String => A
for someA
), and ignore it otherwise:Now the following will give the result you want in both 1.2.4 and 2.0.0-M1:
You could also write your own type class on the model of
Filter
,FilterAux
(orFilter.Aux
), etc.—and doing so would be a good exercise if you're trying to get the hang of Shapeless—butfoldRight
is a lot simpler.Update: actually, for what it's worth, there's a slightly more concise way to do this with
flatMap
:I personally find the
foldRight
version a little more obvious, but this one's also pretty elegant.In response to your comment: you can make the solution a little more generic like this:
But you're still going to need that last step where you create the higher rank function as an object (see e.g. this answer and Miles's comment there for some discussion of this issue).