很容易按类型过滤HList
无形:
val hlist = 1 :: 2 :: "3" :: true :: false :: HNil
hlist.filter[Int]
但是如何制作我的自定义类型过滤器?我想要那样的smth:例如我得到了一些函数的列表:
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
因此,在使用此过滤器后,将构建从类型String
到其他类型的函数列表。
我有一个想法,为此使用map,但它没有成功。
版
有关我的评论的更多信息:
我试图在地图中测试这个想法:
所以,如果我有一些列表(让我们使用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
非常有趣,为什么编译和工作不正确?因为我认为它不起作用,导致对象不能以这种方式采取类型参数...
答案 0 :(得分:14)
最简单的方法是使用折叠。首先,我们需要一个多态函数,如果它具有所需的类型(String => A
对于某些A
),则将每个项添加到累加器中,否则忽略它:
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](_ :: _)
}
现在,以下内容将在1.2.4和2.0.0-M1中给出您想要的结果:
val filtered = hflist.foldRight(HNil)(keepStringFunc)
你也可以在Filter
,FilterAux
(或Filter.Aux
)等模型上编写自己的类型类 - 如果你这样做,这样做会很好试图获得无形的悬念 - 但是foldRight
要简单得多。
更新:实际上,对于它的价值,使用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
我个人认为foldRight
版本更加明显,但这个版本也非常优雅。
回应您的评论:您可以使解决方案更加通用:
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
但是你仍然需要最后一步,你可以创建更高级别的功能作为一个对象(参见例如this answer和Miles的评论,以便对此问题进行一些讨论)。