为啥方差注释会导致 Scala 无法推断出这种子类型关系?

Posted

技术标签:

【中文标题】为啥方差注释会导致 Scala 无法推断出这种子类型关系?【英文标题】:Why does a variance annotation cause this subtyping relation not to be inferred by Scala?为什么方差注释会导致 Scala 无法推断出这种子类型关系? 【发布时间】:2014-06-20 23:37:45 【问题描述】:

在代码中

  sealed trait Node[+T]
  case class I[C]() extends Node[C => C]

  def test[A, B](n: Node[A => B]) = n match 
    case i: I[c] =>
      val cId: c => c = identity _
      val ab: A => B = cId
  

Scala 给出c => c 不是A => B 的错误。去掉Node[+T]中的variance注解即可解决错误。

我很困惑,因为我相信,在存在差异注释的情况下,匹配 i: I[c] 应该创建规则 (c => c) <:< (A => B),这就是编译该行所需的全部内容。我错过了什么?

【问题讨论】:

函数参数的自变量是 CONTRAvariant。这不是答案,而是猜测。 @MikeG。嗯,我想知道这是否可能涉及,但我看不出是怎么回事——=> 的差异似乎在这里没有发挥作用。当然,如果我是对的,我应该能够在没有函数类型的情况下重现这个示例,但它仍然会失败。也许我会试试看。 经过进一步的实验,这似乎与 =>... 的变化无关,甚至与 => 的差异无关,但似乎与 @ 中的重复类型变量有关987654331@。仍然不确定为什么这很重要。 那很好。我不知道这是否是一个 patmat 错误。我像cmets一样通过动作。 issues.scala-lang.org/browse/SI-8563 我认为问题出在类型差异上。特别是当i: I[C] 匹配时,c =:= A 应该为真。 (因此所有以下语句都应该编译) 【参考方案1】:

免责声明:c 在运行时被删除,您的匹配将无法正常工作。您正在匹配 I[_]

如果您的 Node 是不变的,Node[A]Node[B] 的子类,仅当且仅当 A=B。这迫使

n 传递给test[A, B](n: Node[A => B]) 成为真正的Node[A => B]

如果你推理失败,如果你的 n 与模式 I[Something] 匹配任何 Something,A 和 B 必须是 Something 类型

如果 Node 是协变的,由于 Function1[-A,+B] 的定义,您可以调用

test[A,B](n) 其中nNode[A1 =>B1] 其中A1>:AB1<:B (等式1)

因此,如果您的 nI[C] 匹配,则意味着 A1 = CB1 = C

如果你替换等式1中的C,你会得到C >: AC<:B(等式2)

因此下面的赋值不再有效

f: A => B = C => C 

为了使左侧可以从右侧分配,我们需要 C => CFunction1[-A,+B]

这意味着 A >: CB <: C 但从等式 2 我们知道这不成立(除了 C = A 和 C = B 的情况,并且没有证据表明情况如此,除非您的节点是不变的

【讨论】:

以上是关于为啥方差注释会导致 Scala 无法推断出这种子类型关系?的主要内容,如果未能解决你的问题,请参考以下文章

为啥 Crystal 不能在初始化程序中推断出这种类型?

为啥 OCaml 中的模块类型注释会导致此代码无法编译?

Scala 运算符 #> 导致编译错误,但不是 &> - 为啥?

scala学习遇到的坑

为啥 Scala 类型推断在这里失败?

为啥 TypeScript 在使用 concat 减少数组时会推断出“从不”类型?