无形Hlist列表中元素的参数过滤

时间:2014-09-09 15:05:07

标签: scala shapeless

简化用例

sealed trait T1
case object Foo extends T1
case object Bar extends T1

sealed trait T2
case object Bip extends T2
case object Bop extends T2

case class Partitioner(v1: T1, v2: T2)

trait WithPartition { self =>
  def pt: Partitioner

  def byT1(t1: T1): Boolean = self.pt.v1 == t1

  def byT2(t2: T2): Boolean = self.pt.v2 == t2
}

case class PSetOne(pt: Partitioner, extraOne: Int) extends WithPartition

case class PSetTwo(pt: Partitioner, extraTwo: Int) extends WithPartition

// create lists

val ls1 = for {
  p1 <- List(Foo,Bar)
  p2 <- List(Bip,Bop)
  n <- 1 to 10
} yield PSetOne(Partitioner(p1,p2),n)

val ls2 = for {
  p1 <- List(Foo,Bar)
  p2 <- List(Bip,Bop)
  n <- 1 to 10
} yield PSetTwo(Partitioner(p1,p2),n)

// So I can filter on the list 

ls2.filter{x => x.byT1(Foo)}

// ls1 ++ ls2 => List[Product with Serializable with WithPartition] 
// but prefer to retain type using HList

val hAll = ls1 :: ls2 :: HNil

//  I can filter if I explicity supply the case object 
object parFoo extends Poly1 {
  implicit def casePset1 = at[List[PSetOne]](_.filter{x => x.byT1(Foo)})
  implicit def casePset2 = at[List[PSetTwo]](_.filter{x => x.byT1(Foo)})
}

hAll.map(parFoo)

我希望能够做的是将Partition值作为参数传递给能够 做点什么

hAll.map(parT1(Foo))

我如何指定对象parT1,以便它可以使用T1对象作为过滤器的参数,如上面的香草列表示例

1 个答案:

答案 0 :(得分:0)

我调查了重复的参考文​​献但该技术超出了我的理解并适用于上述情况。我找到了一种替代的非基于形状的解决方案,即用一些额外的类型信息来修改代码。

trait PSet

type PSP = PSet with WithPartition

case class PSetOne(pt: Partitioner, extraOne: Int) extends PSet with WithPartition

case class PSetTwo(pt: Partitioner, extraTwo: Int) extends PSet with WithPartition

// create lists with type ascription

val ls1 = for {
  p1 <- List(Foo,Bar)
  p2 <- List(Bip,Bop)
  n <- 1 to 10
} yield PSetOne(Partitioner(p1,p2),n) : PSP

val ls2 = for {
  p1 <- List(Foo,Bar)
  p2 <- List(Bip,Bop)
  n <- 1 to 10
} yield PSetTwo(Partitioner(p1,p2),n) : PSP

val als = ls1 ++ ls2 
// now gives me List[PSP] and I can

val foos = als.filter{x => x.byT1(Foo)}
val bips = als.filter{x => x.byT2(Bip)} 

// and still extract by case class

val foos1 = foos.collect{case f: PSetOne => f}

我对此并不完全满意(虽然我确实使用了PSP的类型别名:))但它现在可以按照我的需要进行。

如果有人可以发布基于无形的解决方案,我将不胜感激,尤其是帮助我提高理解力。