如何映射Nat的无形状HList



我有一个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 ?

问题是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的东西。

窍门就是在case中添加一个类型参数:
object NatToString extends Poly1 {
  implicit def caseNat[N <: Nat] = at[N](_.toString)
}

您会发现通常直接使用Nat并不是您想要的—您几乎总是需要一个特定的子类型。

最新更新