用于无形 Hlist 的通用 Poly2 文件夹
Generic Poly2 Folder case for shapeless Hlist
我正在尝试转换以下 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 中的任何类型,而不必编写每个案例
首先是字面答案。请注意,您的大多数 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)
}
请注意,如果您在 default
中切换参数顺序,您甚至不需要 none
大小写。
另请注意,您可能希望使用 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
—例如静态类型为 Option[A]
的 Some[A]
将被过滤掉。这使它有点无用(至少我看不到实际用途),但如果您在编译时不知道 Option
是否为空
我正在尝试转换以下 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 中的任何类型,而不必编写每个案例
首先是字面答案。请注意,您的大多数 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)
}
请注意,如果您在 default
中切换参数顺序,您甚至不需要 none
大小写。
另请注意,您可能希望使用 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
—例如静态类型为 Option[A]
的 Some[A]
将被过滤掉。这使它有点无用(至少我看不到实际用途),但如果您在编译时不知道 Option
是否为空