I toyed around with HList and the following works as expected:
val hl = 1 :: "foo" :: HNil
val i: Int = hl(_0)
val s: String = hl(_1)
However, I can't get the following piece of code working (let's assume for a moment random access on lists is a smart idea ;-)):
class Container(hl: HList) {
def get(n: Nat) = hl(n)
}
val container = new Container(1 :: "foo" :: HNil)
val i: Int = container.get(_0)
val s: String = container.get(_1)
I'd like to have get
return an Int
and String
according to it's parameter. I assume, if possible at all, I have to use Aux
or at
but I'm not sure how to do this.
Try something along these lines,
scala> import shapeless._, nat._, ops.hlist._
import shapeless._
import nat._
import ops.hlist._
scala> class Container[L <: HList](hl: L) {
| def get(n: Nat)(implicit at: At[L, n.N]): at.Out = hl[n.N]
| }
defined class Container
scala> val container = new Container(1 :: "foo" :: HNil)
container: Container[shapeless.::[Int,shapeless.::[String,shapeless.HNil]]] = ...
scala> container.get(_0)
res1: Int = 1
scala> container.get(_1)
res2: String = foo
The first crucial difference here is that rather than typing hl
as plain HList
, which loses all specific information about the types of the elements, we parametrize over the precise type of the argument and preserve its structure as L
. The second difference is that we use L
to index the implicit At
type class instance which is used to perform the indexing in get
.
Also note that because there is an implicit conversion from Int
literals to Nat
's you can write,
scala> container.get(0)
res3: Int = 1
scala> container.get(1)
res4: String = foo
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With