如何使用普通的 Scala 集合压缩 HList?
How to zip an HList with a plain Scala collection?
如何使用 Scala Stream 压缩 HList 以生成成对的 HList?具体来说:
import shapeless._
val a = 1.3 :: true :: "z" :: HNil
val b = Stream.from(1)
val ab: (Double, Int) :: (Boolean, Int) :: (String, Int) :: HNil = ???
trait Zipper[A <: HList, B] {
type Out <: HList
def zip(a: A, bs: Stream[B]): Out
}
implicit def hnilZipper[B] = new Zipper[HNil, B] {
type Out = HNil
def zip(a: HNil, bs: Stream[B]): HNil = HNil
}
implicit def consZipper[Head, Tail <: HList, B](implicit z: Zipper[Tail, B]) = new Zipper[Head :: Tail, B] {
type Out = (Head, B) :: z.Out
def zip(a: Head :: Tail, bs: Stream[B]): Out = {
(a.head, bs.head) :: z.zip(a.tail, bs.tail)
}
}
def zip[A <: HList, B](a: A, b: Stream[B])(implicit z: Zipper[A, B]): z.Out = z.zip(a, b)
正如 Marth 所说,存在安全问题,如果 Stream 比 HList 短,这将失败。但是你可以很容易地将它修改为 return 一个 Option[(A1, B) :: (A2, B) :: ...]
或一个 (A1, Option[B]) :: (A2, Option[B]) :: ...
如果这是一个问题。
可以,但有限制。大多数情况下,您必须指定要压缩的 Scala 集合的所需长度。当然,结果将是两个 HList 中较短者的长度。
import shapeless._
import syntax.std.traversable._ // toHList
val a = 1.3 :: true :: "z" :: HNil // 3 elements
val short_b = Stream.from(1).take(2).toHList[Int::Int::HNil]
val long_b = Stream.from(7).take(5).toHList[Int::Int::Int::Int::Int::HNil]
toHList
returns 和 Option[HList]
所以我们将 map
提取要压缩的 HList
结果。
short_b.map(a zip _) // 2 element result
//res0: Option[(Double, Int) :: (Boolean, Int) :: HNil] =
// Some((1.3,1) :: (true,2) :: HNil)
long_b.map(a zip _) // 3 element result
//res1: Option[(Double, Int) :: (Boolean, Int) :: (String, Int) :: HNil] =
// Some((1.3,7) :: (true,8) :: (z,9) :: HNil)
如何使用 Scala Stream 压缩 HList 以生成成对的 HList?具体来说:
import shapeless._
val a = 1.3 :: true :: "z" :: HNil
val b = Stream.from(1)
val ab: (Double, Int) :: (Boolean, Int) :: (String, Int) :: HNil = ???
trait Zipper[A <: HList, B] {
type Out <: HList
def zip(a: A, bs: Stream[B]): Out
}
implicit def hnilZipper[B] = new Zipper[HNil, B] {
type Out = HNil
def zip(a: HNil, bs: Stream[B]): HNil = HNil
}
implicit def consZipper[Head, Tail <: HList, B](implicit z: Zipper[Tail, B]) = new Zipper[Head :: Tail, B] {
type Out = (Head, B) :: z.Out
def zip(a: Head :: Tail, bs: Stream[B]): Out = {
(a.head, bs.head) :: z.zip(a.tail, bs.tail)
}
}
def zip[A <: HList, B](a: A, b: Stream[B])(implicit z: Zipper[A, B]): z.Out = z.zip(a, b)
正如 Marth 所说,存在安全问题,如果 Stream 比 HList 短,这将失败。但是你可以很容易地将它修改为 return 一个 Option[(A1, B) :: (A2, B) :: ...]
或一个 (A1, Option[B]) :: (A2, Option[B]) :: ...
如果这是一个问题。
可以,但有限制。大多数情况下,您必须指定要压缩的 Scala 集合的所需长度。当然,结果将是两个 HList 中较短者的长度。
import shapeless._
import syntax.std.traversable._ // toHList
val a = 1.3 :: true :: "z" :: HNil // 3 elements
val short_b = Stream.from(1).take(2).toHList[Int::Int::HNil]
val long_b = Stream.from(7).take(5).toHList[Int::Int::Int::Int::Int::HNil]
toHList
returns 和 Option[HList]
所以我们将 map
提取要压缩的 HList
结果。
short_b.map(a zip _) // 2 element result
//res0: Option[(Double, Int) :: (Boolean, Int) :: HNil] =
// Some((1.3,1) :: (true,2) :: HNil)
long_b.map(a zip _) // 3 element result
//res1: Option[(Double, Int) :: (Boolean, Int) :: (String, Int) :: HNil] =
// Some((1.3,7) :: (true,8) :: (z,9) :: HNil)