检查Scala中涉及存在的类型是否相等

时间:2014-10-08 00:02:55

标签: scala existential-type

我正在编写

形式的函数
def test[A,B](a: A, b: B)(implicit eq: A =:= B): Unit = ...

我要求提供AB类型相同的证据。

我希望test(a,a)形式的调用可以为任何a进行编译,但是当a的类型涉及存在时,似乎不是这种情况,例如

case class Foo[T](c: T)
val l = List(Foo(1), Foo(1.0F), Foo(0.0)) // Inferred type: List[Foo[_ >: Double with Float with Int <: AnyVal]]

test(l.head, l.head) // Does not compile, error like: Cannot prove that Foo[_7] =:= Foo[_7].

所以我的问题是:我是否误用了=:=?或者它可能是一个错误?或存在的基本限​​制?或者他们的实施限制?

上下文

我正在测试涉及依赖类型的函数f的返回类型。 我希望它在a中为bval a = f(...); val b = f(...)返回相同的类型,因此我调用test(a, b)。如果ab的类型涉及存在,即使test(a,a)test(b,b)也不会编译,如上所述。

1 个答案:

答案 0 :(得分:3)

Implicit =:=适用于存在类型

scala> implicitly[Foo[_ <: Int] =:= Foo[_ <: Int]]
res0: =:=[Foo[_ <: Int],Foo[_ <: Int]] = <function1>

scala> implicitly[Foo[_ <: Int] =:= Foo[_]]
<console>:10: error: Cannot prove that Foo[_ <: Int] =:= Foo[_].
              implicitly[Foo[_ <: Int] =:= Foo[_]]
                        ^

问题是scala在为函数调用解析隐式时丢失了存在类型 - 这里没有推断出A和B(这就是为什么你看到_7表示并且没有发现含义)。

def test[A,B](a: A, b: B)(implicit eq: A =:= B)

可以使用类型别名来解决:

scala> case class Foo[A](a: A) {type X = A}
defined class Foo

scala> val l = List(Foo(1), Foo(1.0F), Foo(0.0)) // Inferred type: List[Foo[_ >: Double with Float with Int <: AnyVal]]
l: List[Foo[_ >: Double with Float with Int <: AnyVal]] = List(Foo(1), Foo(1.0), Foo(0.0)) 

scala> val k = l.head
k: Foo[_ >: Double with Float with Int <: AnyVal] = Foo(1)

scala> implicitly[k.X =:= k.X]
res15: =:=[_ >: Double with Float with Int <: AnyVal, _ >: Double with Float with Int <: AnyVal] = <function1>

scala> implicitly[k.X =:= _ >: Double with Float with Int <: AnyVal]
res16: =:=[_ >: Double with Float with Int <: AnyVal, _ >: Double with Float with Int <: AnyVal] = <function1> 

但请记住,即使是具有相似签名但来自不同Foo的类型也会有所不同(因为它依赖于路径的类型) - 存在类型是如此存在!