Say that I have a trait Show[T]
such as the one in Scalaz: https://github.com/scalaz/scalaz/blob/scalaz-seven/core/src/main/scala/scalaz/Show.scala#L9
I also have a Shapeless HList
that may look like "1" :: 2 :: 3L :: HNil
.
Is there a way to find the Show
instance for each element and apply shows
such that I end up with "1" :: "2" :: "3L" :: HNil
?
If any element were of a type that did not have an implicit Show
instance in scope I would want a compile error.
I think that if I build up an HList
of the Show
instances I should be able to use zipApply
to get the HList
I want, but I don't know if there is a way to get have Scala infer the HList
of Show
instances instead of me building it up by hand.
If your goal is to apply the Show
instances and you don't otherwise care about building up an HList
of them, the easiest approach is probably to use a polymorphic function:
import scalaz._, Scalaz._, shapeless._
val xs = "1" :: 2 :: 3L :: HNil
object show extends Poly1 {
implicit def forShowable[A: Show] = at[A](_.shows)
}
val strings: String :: String :: String :: HNil = xs map show
You could get an HList
of the instances by changing the Poly1
a bit:
object showInstance extends Poly1 {
implicit def forShowable[A: Show] = at[A](_ => Show[A])
}
In some cases it can be useful to define your own type class to collect evidence that you've got certain type class instances:
trait AllShowable[L <: HList, S <: HList] {
def instances: S
}
implicit object hnilAllShowable extends AllShowable[HNil, HNil] {
def instances = HNil
}
implicit def hlistAllShowable[H: Show, TL <: HList, TS <: HList](
implicit ts: AllShowable[TL, TS]
) = new AllShowable[H :: TL, Show[H] :: TS] {
def instances = Show[H] :: ts.instances
}
But usually mapping with a polymorphic function that requires the instances will work just fine.