微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

具有协方差的交叉点类型

如何解决具有协方差的交叉点类型

考虑以下事项:

trait AA {
    def children: List[AA]
}

trait BB {
    def children: List[BB]
}

class CC extends AA,BB {
    override def children: List[AA] & List[BB] = ???
}

当我们在 children 中覆盖 CC 时,覆盖的方法是顶级方法的合并实体。因此返回类型 List[AA] & List[BB] 是有意义的。

我不明白的是,下面是如何编译的?

class DD extends AA,BB {
    override def children: List[AA & BB] = ???
}

List 是协变的,因此(这里是 proof 的来源):

List[AA & BB] <: List[AA] & List[BB]

DD 只能在 also List[AA] & List[BB] <: List[AA & BB] 时编译。这是真的吗? 如果是这样,则不是 List[AA] & List[BB] =:= List[AA & BB]。请推荐


在我看来,List[AA & BB] =:= List[AA] & List[BB]。考虑一下:

    val xx: List[AA & BB] = ???
    val yy: List[AA] & List[BB] = ???
    
    val z1: List[AA] & List[BB] = xx
    val z2: List[AA & BB] = yy

解决方法

您编写的 DD 要编译,List[AA] & List[BB] 必须是 List[AA & BB] 的子类型。我不明白你为什么这么认为,事实上你错了。方法返回类型是协变的,因此正好相反:List[AA & BB] 必须是 List[AA] & List[BB] 的子类型。而且确实是这样,所以代码没问题。

,

Matthias Berndt 已经回答说编译您的代码不需要 List[AA] & List[BB] <: List[AA & BB]。然而,有一点是它实际上是正确的(List[AA] & List[BB] =:= List[AA & BB] 也是如此)。为什么?

  1. 考虑类型为 x 的值 List[AA] & List[BB]
  2. 它必须同时是 List[AA]List[BB]
  3. 即,AA 的列表和 BB 的列表。
  4. 所以这个列表的任何元素 y 都必须是一个 AA 因为 x 是一个 AA 的列表,一个 BB 因为 {{1 }} 是 x 的列表。
  5. 所以 BB 必须是 y
  6. 由于 AA & BB 的每个元素都具有 x 类型,因此 AA & BB 具有 x 类型。

此推理特定于 List[AA & BB],但它概括了 and not just to covariant types

如果 List 是类型构造函数,那么可以使用以下三个规则简化 C

  • 如果 C[A] & C[B] 是协变的,则 C
  • 如果 C[A] & C[B] ~> C[A & B] 是逆变的,则 C
  • 如果 C[A] & C[B] ~> C[A | B] 是非变体,则发出编译错误

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。