我正在尝试转换以下HList
Some(C(15)) :: None :: Some(B(55)) :: None :: Some(A(195)) :: HNil
到
C(15) :: B(55) :: A(195) :: HNil
这就是我现在所拥有的:
import shapeless._
case class A(value: Int)
case class B(value: Int)
case class C(value: Int)
trait folderLP extends Poly2 {
implicit def default[T, L <: HList] = at[T, L]((acc, t) => acc)
}
object folder extends folderLP {
implicit def none[T, L <: HList] = at[None.type, L]((t, acc) => acc)
implicit def someDiameter[T, L <: HList] = at[Some[C], L]((t, acc) => t.get :: acc)
implicit def someRatio[T, L <: HList] = at[Some[B], L]((t, acc) => t.get :: acc)
implicit def someWidth[T, L <: HList] = at[Some[A], L]((t, acc) => t.get :: acc)
}
val test = Some(C(15)) :: None :: Some(B(55)) :: None :: Some(A(195)) :: HNil
val filtered = test.foldRight[HList](HNil)(folder)
这有效,但我想使这个通用,以便它适用于包含在Some中的任何类型,而无需编写每个案例
答案 0 :(得分:7)
首先是字面答案。请注意,大多数T
类型参数未被使用。您可以使用T
使您的函数与Some[T]
类型的任何元素匹配:
trait folderLP extends Poly2 {
implicit def default[T, L <: HList] = at[T, L]((_, acc) => acc)
}
object folder extends folderLP {
implicit def some[T, L <: HList] = at[Some[T], L]((t, acc) => t.get :: acc)
}
请注意,如果您在none
中切换参数顺序,则甚至不需要default
个案。
另请注意,您可能希望使用filtered
的以下定义:
val filtered = test.foldRight(HNil: HNil)(folder)
这一个将HNil
静态输入为HNil
而不是HList
,这对于你想要做的任何事情都很有用 - 例如试试原始版本上的filtered.length
,然后是此版本。
你甚至不需要折叠这个操作,但flatMap
会这样做:
trait filterLP extends Poly1 {
implicit def any[T] = at[T](_ => HNil)
}
object filter extends filterLP {
implicit def some[T] = at[Some[T]](_.get :: HNil)
}
然后:
val filtered = test.flatMap(filter)
最后,值得注意的是,这仅适用于HList
None
和Some
元素被静态输入为None
和Some
的情况 - 例如,Some[A]
静态输入的Option[A]
将被过滤掉。这使得它有点无用(至少我看不到实际用途),但是如果你在编译时不知道是否{{1},那么就没有任何方法可以执行这种类型级别的过滤器是空的。