I have a HList of Nat, and I want to map over it
object NatToString extends Poly1 {
implicit def caseNat = at[Nat](_.toString)
}
val list = _5 :: _3 :: HNil
list.map(NatToString)
This code doesn't compile and throw:
could not find implicit value for parameter mapper:
shapeless.ops.hlist.Mapper[Main.Nat_to_String.type,shapeless.::[shapeless.Nat._5,shapeless.::[shapeless.Nat._3,shapeless.HNil]]]
But if I do exactly the same thing with Int (or String, or List, etc.) in place of Nat, it works perfectly.
How can I map over an HList of Nat ?
The issue is that Poly1.Case
is not covariant in its type parameter. Consider the following:
trait Foo
trait Bar extends Foo
val foo = new Foo {}
var bar = new Bar {}
object fooIdentity extends Poly1 {
implicit def caseFoo = at[Foo](identity)
}
Now fooIdentity(foo)
will compile, but fooIdentity(bar)
won't.
In your case the members of the HList
are statically typed as _5
and _3
. These are subtypes of Nat
, but NatToString
doesn't care, since its only case is looking for something statically typed as Nat
.
The trick is just to add a type parameter to the case:
object NatToString extends Poly1 {
implicit def caseNat[N <: Nat] = at[N](_.toString)
}
You'll find that in general working with Nat
directly isn't what you want—you'll almost always want a specific subtype.