scala - 无形HList类型检查

标签 scala shapeless type-level-computation

我正在使用Shapeless,并具有以下方法来计算两个HList之间的差异:

  def diff[H <: HList](lst1: H, lst2:H):List[String] = (lst1, lst2) match {
    case (HNil, HNil)                 => List()
    case (h1::t1, h2::t2) if h1 != h2 => s"$h1 -> $h2" :: diff(t1, t2)
    case (h1::t1, h2::t2)             => diff(t1, t2)
    case _                            => throw new RuntimeException("something went very wrong")
  }

由于该方法的两个参数都使用H,因此我希望不同类型的HList不会在此处编译。例如:
diff("a" :: HNil, 1 :: 2 :: HNil)

不应该编译,但是可以编译,并且会产生运行时错误:java.lang.RuntimeException: something went very wrong。我可以对类型参数做些什么,使该方法仅接受具有相同类型的两个边?

最佳答案

不幸的是,基本的HList特性是未参数化的,因此在您的方法调用中,H只是解析为Hlist(实际上,它是任何Hlist的父类(super class)型,而与具体的元素类型无关)。
为了解决这个问题,我们必须对定义进行一些更改,而要依赖于通用类型约束:

def diff[H1 <: HList, H2 <: HList](lst1: H1, lst2: H2)(implicit e: H1 =:= H2): List[String] = (lst1, lst2) match {
  case (HNil, HNil)                 => List()
  case (h1::t1, h2::t2) if h1 != h2 => s"$h1 -> $h2" :: diff(t1, t2)
  case (h1::t1, h2::t2)             => diff(t1, t2)
  case _                            => throw new RuntimeException("something went very wrong")
}

让我们检查:
scala> diff("a" :: HNil, 1 :: 2 :: HNil)
<console>:12: error: Cannot prove that shapeless.::[String,shapeless.HNil] =:= shapeless.::[Int,shapeless.::[Int,shapele
              diff("a" :: HNil, 1 :: 2 :: HNil)
                  ^

scala> diff("a" :: HNil, "b" :: HNil)
res5: List[String] = List(a -> b)

scala> diff("a" :: 1 :: HNil, "b" :: 2 :: HNil)
res6: List[String] = List(a -> b, 1 -> 2)

现在我们仍然可以“作弊”,并将H1和H2显式设置为HList,然后回到平方一。
scala> diff[HList, HList]("a" :: HNil, 1 :: 2 :: HNil)
java.lang.RuntimeException: something went very wrong
  at .diff(<console>:15)
  at .diff(<console>:13)

不幸的是,我认为这不容易解决(虽然是肯定的,但是我没有快速解决方案)。

关于scala - 无形HList类型检查,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31177695/

相关文章:

scala - Scala 背后的可索引数据结构便于理解

scala - 在scala 2.13中,为什么有时无法显式调用类型类?

scala - 使用 Shapeless 将 Map[String,Any] 转换为案例类

scala - 使用Scalaz或Shapeless将选项的元组转换为元组的选项

scala - HList 的无形状类型推断不起作用

scala - 如何在 scalaz 中将 Throwable\/List[Throwable\/A] 排序为 Throwable\/List[A]?

java - 是否可以为现有的 Java bean 类获取 Scala 案例类?

scala - Play 框架堆栈跟踪日志记录和日志记录配置

scala - 使用 Shapeless + LabelledGenerics 一般将一个类变形为另一个类