在Shapeless HList中查找类型类实例

8
假设我有一个名为Show[T]的trait,就像Scalaz中的那个一样:https://github.com/scalaz/scalaz/blob/scalaz-seven/core/src/main/scala/scalaz/Show.scala#L9。同时,我还有一个Shapeless的HList,可能看起来像这样:"1" :: 2 :: 3L :: HNil
有没有一种方法可以找到每个元素的Show实例并应用shows,使我最终得到"1" :: "2" :: "3L" :: HNil
如果任何元素的类型在范围内没有隐式的Show实例,我希望会出现编译错误。
我认为,如果我建立一个Show实例的HList,我应该能够使用zipApply来获得我想要的HList,但我不知道是否有一种方法让Scala推断出Show实例的HList,而不是手动构建它。
1个回答

9
如果您的目标是应用 Show 实例,并且您不关心构建它们的 HList,那么最简单的方法可能是使用多态函数:
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

您可以通过对Poly1稍作修改来获取实例的HList

object showInstance extends Poly1 {
  implicit def forShowable[A: Show] = at[A](_ => Show[A])
}

有时候定义自己的类型类来收集特定类型类实例的证据是很有用的:

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
}

但通常使用需要实例的多态函数进行映射就可以正常工作。


2
Travis,你是如何这么快地回答的呢?当我发布这个问题时,我有一种感觉,那就是答案要么是“这是不可能的”,要么是解决方案非常简单,以至于我会感到很愚蠢。很高兴看到答案是后者 :) - ceedubs
3
我正在一个周六的早晨努力工作一个无尽的项目,所以能够回答这样的问题是一个非常受欢迎的士气提升。而且我不确定任何关于Shapeless的良好提问都会被认为是“愚蠢”的。 - Travis Brown

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接