【问题标题】:Why certain recursive types fail to compile为什么某些递归类型无法编译
【发布时间】:2017-09-04 04:08:07
【问题描述】:

我遇到了我无法理解的类型检查错误。两段代码相似,但只有一段可以编译。编译器给出完全无用的错误信息:

错误:类型参数 [I] 不符合类型 DY 的类型参数界限 [I <: sample.this.y>

有问题的代码:

trait Sample {
  type X
  type DX[I <: X] <: X
  type Y = Aux[X]
  type DY[I <: Y] <: Y
  type Z = Bux[X]
  type DZ[I <: Z] <: Z
  type DW[I <: Z#C] <: Z#C
}
type Aux[I] = Sample { type X = I }

trait Dep {
  type B
  type C = Aux[B]
}
type Bux[A] = Dep { type B = A }

type UseX[I <: S#X, S <: Sample] = S#DX[I] // ok
type UseY[I <: S#Y, S <: Sample] = S#DY[I] // fails
type UseZ[I <: S#Z, S <: Sample] = S#DZ[I] // ok
type UseW[I <: S#Z#C, S <: Sample] = S#DW[I] // fails

为什么我不能引用类型本身?


更新

我和我写这个问题时一样困惑。但我仍然设法欺骗编译器完成他的工作。这只会加剧我的困惑。

问题是基于类型绑定接受或拒绝相同类型的参数。如果类型绑定与参数相同(因此引入递归),则它被拒绝。但是,如果我将递归包装在一个类型中,它通常会被接受。所以我只需要中继递归调用

trait Sample {
  type X
  type Y = Aux[X]
  type Z = Bux[X]
  type DY[I <: Y] <: Y
  type DD[I <: Z] = DY[I#C]
}

type UseY[I <: S#Y, S <: Sample] = S#DY[I] // still fails
type UseD[I <: S#Z, S <: Sample] = S#DD[I] // miraculously works

但它需要将每个类型级别的调用包装在 Bux 包装器类型中。

【问题讨论】:

  • 添加编译错误会有所帮助
  • 我把错误放在代码前面。
  • 它有一个循环,设计成这样?
  • 是的。我在实现某种类型列表时遇到错误,该类型列表本质上是递归结构。之后,我将代码简化为最小的可重现示例。请注意,使用Z 仍然可以,即使它包含递归但没有显式调用它。
  • 这个编译:type UseY[I &lt;: S#Y, S &lt;: Aux[I]] = S#DY[I]type UseW[I &lt;: S#Z#C, S &lt;: Aux[I]] = S#DW[I]

标签: scala types


【解决方案1】:

所以,S#Y 的意思是“一些 类型Y,在S任何 实例中定义”。 另一方面,type DY[I &lt;: Y] 表示“I 必须是在 this 实例中声明的Y 的子类”。

所以,当你说type UseY[I &lt;: S#Y, S &lt;: Sample] = S#DY[I] 时,它失败了,因为I 被限制为来自一些 SY 的子类,但DY 希望它是相同 S 的子类,其中声明了 DY

【讨论】:

  • 相同的逻辑适用于XZ,但它们有效,只有Y 失败。
猜你喜欢
  • 2015-06-07
  • 2023-03-11
  • 1970-01-01
  • 2020-11-20
  • 2020-12-28
  • 2020-05-02
  • 1970-01-01
  • 2022-02-07
  • 1970-01-01
相关资源
最近更新 更多