没有协变注释的更高的kinded存在

时间:2014-02-07 11:57:09

标签: scala covariance existential-type higher-kinded-types

当尝试在Scala中使用更高的kinded存在时,我遇到了以下问题:

trait A[H[_]]
trait Test {
  val l: A[List]
  // [error] type mismatch;
  // [error]  found   : A[List]
  // [error]  required: A[_[_] <: Any]
  // [error] Note: List <: Any, but trait A is invariant in type H.
  // [error] You may wish to define H as +H instead. (SLS 4.5)
  val x: A[B] forSome { type B[_] } = l
}

在编译器建议的情况下向H添加协变注释。如果我不希望H是协变的,有没有办法解决这个问题呢?

1 个答案:

答案 0 :(得分:0)

该示例的略微变化提供了更有用的错误消息:

scala> l: (A[B] forSome { type B[_] })
<console>:10: error: type mismatch;
 found   : A[List]
 required: A[_[_] <: Any]
Note: List <: Any, but trait A is invariant in type H.
You may wish to define H as +H instead. (SLS 4.5)
              l: (A[B] forSome { type B[_] })
              ^
<console>:10: error: can't existentially abstract over parameterized type B
              l: (A[B] forSome { type B[_] })
               ^

查找此错误会将我们带入编译器中的TODO。

由于存在类型是disappear,根据Odersky的电子邮件,我认为这个限制不会被修复。然而,Martin Odersky的email也提醒我们,存在类型等同于抽象类型。因此,上面的例子可以编码如下:

scala> trait A { type H[_] }
defined trait A

scala> val l: A {type H[X] = List[X]} = null
l: A{type H[X] = List[X]} = null

scala> l: A
res0: A = null

类型应用程序在语法上是丑陋的,但将值转换为存在性变得微不足道(也是在编译器中实现,这是Odersky的观点的一部分)。

对存在性进行编码有用的是类型成员不必实例化。所以,要编码A[_],我们可以写:

scala> class A { type T }
defined class A

scala> new A
res1: A = A@3a7049a6

这里令人困惑的是,这不适用于对象:

scala> object B { type T }
<console>:8: error: only classes can have declared but undefined members
       object B { type T }
                       ^

但我最近认为这是一个错误 - 请参阅here以获取澄清规范(由Adriaan Moors批准)的拉取请求,并here获取我的错误报告和单行修复编译器(仍在等待审查)。