Reputation: 149
Writting algorithm on HList
, I need a zipWithIndex
function. It is not at the shapeless library by now, so I decided to implement it.
It is quite obvious that it might be implemented as
hlist.zip(indexes)
where indexes
is the HList
of the indexes (0..n), that probably could be obtained this way:
val indexes = Nat._0 until hlist.length
Issue here is that Nat
doesn't have until
method. I haven't found any Witness
for the HList
index to use with HList.map
.
What is the method I could use to obtain HList
of Nat
s starting with Nat._0
till hlist.length
?
Upvotes: 4
Views: 414
Reputation: 139028
It might make sense to add something like this to 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()
Now you can write zipWithIndex
pretty cleanly:
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())
And then:
import nat._
type Expected = (Int, _0) :: (Symbol, _1) :: (String, _2) :: HNil
val xs: Expected = zipWithIndex(1 :: 'a :: "foo" :: HNil)
You could also use a fold or a ZippedWithIndex[L <: HList]
type class, both of which might be a little more concise, but less clearly composed out of independently useful pieces like Range
.
Upvotes: 6