在scala中“不符合特征生成器的类型参数范围”是什么意思?

时间:2019-03-12 21:43:46

标签: scala types type-systems generic-type-argument abstract-type

我有以下简单程序,分别为类型参数和抽象类型别名定义2个相同的上限:

package scala.spike.typeBoundInference

object Example1 {
  trait Domain {
  }

  trait Impl {

    type DD <: Domain
    type GG <: StaticGraph[DD]

    type A1
    type A2
    type A3
    // ... this type list can go very long
    // so inlining them as generic type parameters is impossible


    final type Builder = StaticGraph.Builder[DD, GG]
  }

  trait DSL[I <: Impl] {

    val impl: StaticGraph.Builder[I#DD, I#GG]
  }

  trait StaticGraph[T <: Domain] {}

  object StaticGraph {

    trait Builder[D <: Domain, G <: StaticGraph[D]] {}

  }
}

但是,scala拒绝编译它:

  

错误:(16,27)类型参数[I#DD,I#GG]不符合特征   生成器的类型参数范围[D <:   scala.spike.typeBoundInference.Example1.Domain,G <:   scala.spike.typeBoundInference.Example1.StaticGraph [D]]       val impl:StaticGraph.Builder [I#DD,I#GG]

这里可能出什么问题了?

  • DD <:域检查

  • GG <:StaticGraph [DD]检查

scala没有理由认为它不安全。

同时,我发现如果将类StaticGraph [T]声明为协变scala编译器,则编译器将成功运行。这甚至更糟(由于某些原因,StaticGraph [T]必须是不变的),因为类型绑定GG <:StaticGraph [DD]意味着如果确定了DD类型,则GG是StaticGraph [DD]的子类,但不是必需的StaticGraph [Domain]的子类,这正是我想要的。

更新1 :我已经阅读了所有答案和评论,并以某种方式给人的印象是,核心原因是,对于{{1 }},类型绑定只能保证该类型

iImpl

但不是i.DD <:< Impl#DD

因此Imp#GG <:< StaticGraph[Impl#DD]也不能得到保证。

但是,我已经做了一个快速实验来验证这个想法,但事实并非如此:

StaticGraph[i.DD] <:< StaticGraph[Impl#GG]

在这种情况下,编译器会抛出错误:

  

错误:(19,10)覆盖特征Impl中类型GG的边界<:   scala.spike.TypeBoundInference.Example1.StaticGraph [scala.spike.TypeBoundInference.Example1.Impl1.DD];   GG类型不兼容       类型GG = StaticGraph [Domain]

如果您认为某些情况下类型约束不成立,可以举个反例吗?

UPDATE2 :根据答案,这是真的:

i.GG <:< StaticGraph[i.DD]

但这可能是错误的:

object Example1 { trait Domain {} class D1 extends Domain {} trait Impl { type DD <: Domain type GG <: StaticGraph[DD] } class StaticGraph[T <: Domain] {} object Impl1 extends Impl { type DD = D1 type GG = StaticGraph[Domain] } //or this: val impl = new Impl { type DD = D1 type GG = StaticGraph[Domain] } }

因此在DSL上下文中,这也可能是错误的:

i.GG <:< StaticGraph[i.DD](3)

但这只是难题的一部分,为了证明它的类型不安全,我们必须构造一个使条件(3)无效的DSL [I]的反例。因此,仍然存在一个老问题:是否可以构建一个反例?

1 个答案:

答案 0 :(得分:0)

好,问题已解决:

import scala.language.higherKinds

object Example5 {

  trait Domain {}
  trait D1 extends Domain

  trait Impl {

    type DD <: Domain
    type GG[T <: Domain] <: StaticGraph[T]
  }

  trait DSL[I <: Impl] {

    val impl: Builder[I#DD, I#GG]
  }

  trait StaticGraph[T <: Domain] {}

  trait Builder[D <: Domain, G[T <: Domain] <: StaticGraph[T]] {}
}

我不敢相信我必须对这种平庸的事物使用更高的种类:-<< / p>

为什么编译?它解耦类型约束,并将其延迟到必要时。 (这是我能想到的唯一解释)