简体   繁体   中英

How map a shapeless HList of Nat

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM