通过隐式测试两个scala无形HList类型的等价性

时间:2017-11-21 19:24:38

标签: scala shapeless implicits

我有兴趣测试两个HList异构记录是否相同&#34 ;;也就是说,它们具有相同的键/值对,但不一定是相同的顺序。是否有预定义的类型谓词执行EquivHLists在下面的代码片段中执行的操作?

// shapeless heterogeneous records with "equivalent" types.
// these should compile if given as the arguments to 'f' below.
val hrec1 = ("a" ->> 1) :: ("b" ->> 2) :: HNil
val hrec2 = ("b" ->> 2) :: ("a" ->> 1) :: HNil

// only compiles if two HList records contain same information
def f(hr1: H1 <: HList, hr2 : H2 <: HList)(implicit equiv: EquivHLists[H1, H2]) = {
  // biz logic
}

2 个答案:

答案 0 :(得分:4)

我相信Align[M,L]类型类支持您想要的内容,它允许您重新排列一个hlist的元素以匹配具有相同类型的另一个hlist的顺序。

这是我认为你想要的功能。它将告诉您两个等效的hlists是否对每种类型具有相同的值。如果两个列表没有相同的类型,则不会编译。

import shapeless._
import ops.hlist._

def equiv[H <: HList, L <: HList]
  (h : H, l : L)(implicit align: Align[H, L]): Boolean = align(h) == l

scala> equiv(3 :: "hello" :: HNil, "hello" :: 3 :: HNil)
res11: Boolean = true

scala> equiv(4 :: "hello" :: HNil, "hello" :: 3 :: HNil)
res12: Boolean = false

scala> equiv(4 :: "hello" :: HNil, "hello" :: 3.0 :: HNil)
<console>:19: error: could not find implicit value for parameter align: shapeless.ops.hlist.Align[Int :: String :: shapeless.HNil,String :: Double :: shapeless.HNil]

编辑:经过一些进一步的实验,如果hlists有多个相同类型的值,这将给出漏报:

scala> equiv(3 :: "hello" :: 4 :: HNil, 4 :: "hello" :: 3 :: HNil)
res14: Boolean = false

这是因为Align的工作方式:它基本上只迭代一个hlist,并以相同的类型拉出另一个的第一个元素。但是,如果您使用单身类型的文字,那么这不应该是一个问题。

所以这个 使用上述记录至少与键有关:

scala> equiv(hrec1, hrec2)
res16: Boolean = true

//change one of the keys
scala> val hrec3 = ("c" ->> 2) :: ("a" ->> 1) :: HNil
hrec3: Int with shapeless.labelled.KeyTag[String("c"),Int] :: Int with shapeless.labelled.KeyTag[String("a"),Int] :: shapeless.HNil = 2 :: 1 :: HNil

scala> equiv(hrec1, hrec3)
<console>:27: error: could not find implicit value for parameter align ...

//change one of the values, it compiles but returns false
scala> val hrec4 = ("b" ->> 2) :: ("a" ->> 3) :: HNil
hrec4: Int with shapeless.labelled.KeyTag[String("b"),Int] :: Int with shapeless.labelled.KeyTag[String("a"),Int] :: shapeless.HNil = 2 :: 3 :: HNil

scala> equiv(hrec1, hrec4)
res18: Boolean = false

答案 1 :(得分:0)

def f(hr1: H1 <: HList, hr2 : H2 <: HList)(implicit equiv: H1 =:= H2) = {
  // biz logic
}

我相信这应该做你想要的,你试过吗?