【问题标题】:Checking the equality of types involving existentials in Scala在 Scala 中检查涉及存在的类型的相等性
【发布时间】:2015-07-07 23:59:16
【问题描述】:

我在写表单的函数

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 的返回类型。 我希望它在val a = f(...); val b = f(...) 中为ab 返回相同的类型,因此我调用test(a, b)。如果ab 的类型涉及existentials,即使test(a,a)test(b,b) 也不会编译,如上所述。

【问题讨论】:

    标签: scala existential-type


    【解决方案1】:

    隐式 =:= 适用于存在类型

    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 的类型也会有所不同(因为它是依赖于路径的类型) - 存在类型是如此存在!

    【讨论】:

    • 好答案。但我仍然不明白为什么它在问题案例中失败。这是什么意思:it becomes unbound here
    • 此外,如果这行得通:implicitly[Foo[_ &gt;: Double with Float with Int &lt;: AnyVal] =:= Foo[_ &gt;: Double with Float with Int &lt;: AnyVal]] 为什么不行?
    • 测试函数在 A、B 存在时对它们进行某种编译时擦除(我认为可以在编译器中修复它),因此 A 和 B 变为 _7 - 并且没有隐含对于这种内部存在类型是可能的,因此隐式 [_7 =:= _7] 失败。在您的示例中,存在类型是已知的 - 所以它工作正常。
    • def t[A,B](n:A, x:B) = println(n+" "+x) t(l.head, l.head) 有效。我仍然不完全理解 cmets 中的原因:)。在我看来,这似乎是一个编译器警告。 `
    • _n 是一个非推断类型表示 - 它只是在解析隐式时没有推断出来。实际上,你在函数中调用什么并不重要——因为即使隐含地也不适用于泛型类型。
    猜你喜欢
    • 2017-11-28
    • 2012-02-23
    • 2015-11-23
    • 2017-11-24
    • 1970-01-01
    • 1970-01-01
    • 2017-01-20
    • 2012-07-12
    • 2019-03-17
    相关资源
    最近更新 更多