【问题标题】:Higher kinded existentials without covariant annotation没有协变注释的高级存在
【发布时间】:2014-02-11 09:32:29
【问题描述】:

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

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 是协变的,有没有办法解决这个问题?

【问题讨论】:

  • 我刚刚意识到错误在于对 x 的赋值,所以现在我明白为什么您的示例有意义了。

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


【解决方案1】:

对示例稍作改动会提供更有用的错误消息:

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。

根据 Odersky 的电子邮件,由于存在类型将转到 disappear,因此我认为不会修复此限制。不过,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 获取我的错误报告和对编译器的单行修复(仍在等待供审查)。

【讨论】:

    猜你喜欢
    • 2015-12-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-07-17
    • 1970-01-01
    • 1970-01-01
    • 2021-12-02
    相关资源
    最近更新 更多