Jea*_*ean 5 generics scala fold hlist shapeless
我正在尝试转换以下HList
Some(C(15)) :: None :: Some(B(55)) :: None :: Some(A(195)) :: HNil
Run Code Online (Sandbox Code Playgroud)
至
C(15) :: B(55) :: A(195) :: HNil
Run Code Online (Sandbox Code Playgroud)
这就是我现在所拥有的:
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)
Run Code Online (Sandbox Code Playgroud)
这是有效的,但我想使这个通用,以便它适用于包含在Some中的任何类型,而无需编写每个案例
首先是字面答案.请注意,大多数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)
}
Run Code Online (Sandbox Code Playgroud)
请注意,none如果切换参数的顺序,甚至不需要这种情况default.
另请注意,您可能希望使用以下定义filtered:
val filtered = test.foldRight(HNil: HNil)(folder)
Run Code Online (Sandbox Code Playgroud)
这个将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)
}
Run Code Online (Sandbox Code Playgroud)
然后:
val filtered = test.flatMap(filter)
Run Code Online (Sandbox Code Playgroud)
最后,值得注意的是,这只会HList在None和Some静态输入元素的位置上起作用,None而Some-a Some[A]例如静态输入Option[A]将被过滤掉.这使得它有点无用(至少我看不到实际用途),但是如果你不知道在编译时是否Option为空或者没有任何方法可以执行这种类型级别的过滤器不.