8

很容易HList按类型过滤无形:

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

但是如何制作我的自定义类型过滤器?我想要那样的东西:例如,我得到了一些函数的列表:

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将构建从类型到其他类型的函数列表。

我有一个想法为此使用地图,但没有成功。

有关我的评论的更多信息:

我试图在地图中测试这个想法:

因此,如果我有一些列表(让我们使用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

非常有趣,为什么它编译和工作不正确?因为我认为它不起作用,导致对象不能以这种方式接受类型参数......

4

1 回答 1

15

最简单的方法是使用折叠。首先,我们需要一个多态函数,如果它具有所需的类型(String => A对于 some 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(or ) 等的模型上编写你自己的类型类Filter.Aux——如果你想掌握 Shapeless 的窍门,这样做会是一个很好的练习——但是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's comment there 对这个问题的一些讨论)。

于 2013-11-10T19:24:33.010 回答