我有一个Nat的HList,我想要映射它
object NatToString extends Poly1 {
implicit def caseNat = at[Nat](_.toString)
}
val list = _5 :: _3 :: HNil
list.map(NatToString)
此代码无法编译并抛出:
无法找到参数映射器的隐含值:
shapeless.ops.hlist.Mapper [Main.Nat_to_String.type,不成形。:: [shapeless.Nat._5,不成形。:: [shapeless.Nat._3,shapeless.HNil]]]
但是如果我用Int(或String,或者List等)代替Nat做同样的事情,那就完美了。
如何映射Nat的HList?
答案 0 :(得分:5)
问题是Poly1.Case
在其类型参数中不是协变的。请考虑以下事项:
trait Foo
trait Bar extends Foo
val foo = new Foo {}
var bar = new Bar {}
object fooIdentity extends Poly1 {
implicit def caseFoo = at[Foo](identity)
}
现在fooIdentity(foo)
会编译,但fooIdentity(bar)
赢了
在您的情况下,HList
的成员被静态输入为_5
和_3
。这些是Nat
的子类型,但NatToString
并不关心,因为它唯一的情况是寻找静态类型为Nat
的内容。
诀窍就是在案例中添加一个类型参数:
object NatToString extends Poly1 {
implicit def caseNat[N <: Nat] = at[N](_.toString)
}
您会发现,与Nat
直接合作并不是您想要的 - 您几乎总是想要一个特定的子类型。