在HList
上编写算法,我需要一个zipWithIndex
函数。它现在不在无形图书馆,所以我决定实施它。
很明显它可以实现为
hlist.zip(indexes)
其中indexes
是索引的HList
(0..n),可能就是这样获得的:
val indexes = Nat._0 until hlist.length
此处的问题是Nat
没有until
方法。我找不到与Witness
一起使用的HList
索引HList.map
。
从HList
到Nat
开始,我可以用Nat._0
hlist.length
来获取{{1}}的方法是什么?
答案 0 :(得分:6)
向Shapeless添加这样的东西可能是有意义的:
import shapeless._, ops.hlist.Prepend
trait Range[A <: Nat, B <: Nat] extends DepFn0 { type Out <: HList }
object Range {
type Aux[A <: Nat, B <: Nat, Out0 <: HList] = Range[A, B] { type Out = Out0 }
implicit def emptyRange[A <: Nat]: Aux[A, A, HNil] = new Range[A, A] {
type Out = HNil
def apply(): Out = HNil
}
implicit def slightlyBiggerRange[A <: Nat, B <: Nat, OutAB <: HList](implicit
rangeAB: Aux[A, B, OutAB],
appender: Prepend[OutAB, B :: HNil],
witnessB: Witness.Aux[B]
): Aux[A, Succ[B], appender.Out] = new Range[A, Succ[B]] {
type Out = appender.Out
def apply(): Out = appender(rangeAB(), witnessB.value :: HNil)
}
}
def range[A <: Nat, B <: Nat](implicit r: Range[A, B]): r.Out = r()
现在你可以非常干净地写出zipWithIndex
:
import ops.hlist.{ Length, Zip }
def zipWithIndex[L <: HList, S <: Nat, R <: HList, Out <: HList](l: L)(implicit
len: Length.Aux[L, S],
range: Range.Aux[nat._0, S, R],
zipper: Zip.Aux[L :: R :: HNil, Out]
): Out = l.zip(range())
然后:
import nat._
type Expected = (Int, _0) :: (Symbol, _1) :: (String, _2) :: HNil
val xs: Expected = zipWithIndex(1 :: 'a :: "foo" :: HNil)
您还可以使用折叠或ZippedWithIndex[L <: HList]
类型类,这两种类型可能更简洁一些,但不太清楚地由独立有用的作品组成,例如Range
。