在scala中“不符合特征生成器的类型参数范围"是什么意思? [英] What does 'do not conform to trait Builder's type parameter bounds' mean in scala?

查看:130
本文介绍了在scala中“不符合特征生成器的类型参数范围"是什么意思?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have the following simple program that defines 2 identical upper bounds for type parameter and abstract type alias respectively:

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拒绝编译它:

However, scala refuse to compile it:

错误:(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]

Error:(16, 27) type arguments [I#DD,I#GG] do not conform to trait Builder's type parameter bounds [D <: scala.spike.typeBoundInference.Example1.Domain,G <: scala.spike.typeBoundInference.Example1.StaticGraph[D]] val impl: StaticGraph.Builder[I#DD, I#GG]

这里可能出什么问题了?

What could possibly go wrong here?

  • DD< ;:域检查

  • DD <: Domain check

GG< ;: StaticGraph [DD]检查

GG <: StaticGraph[DD] check

scala没有理由认为这是不安全的.

there is no reason scala think it is unsafe.

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

In the meantime, I found that if class StaticGraph[T] is declared as covariant scala compiler will run successfully. This is even worse (for some reason StaticGraph[T] has to be invariant), as type bound GG <: StaticGraph[DD] means that if type DD is determined, then GG is a subclass of StaticGraph[DD], but not necessary a subclass of StaticGraph[Domain], which is exactly what I want here.

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

UPDATE 1: I've read all the answers and comments and somehow got the impression that the core reason is that there is no guarantee that for any instance i of Impl, the type bound only guarantee that type

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

但不是StaticGraph[i.DD] <:< StaticGraph[Impl#GG]

因此也不能保证i.GG <:< StaticGraph[i.DD].

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

However, I've done a quick experiment to verify this idea, which turns out to be not ture:

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]
  }
}

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

In this case compiler throw an error:

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

Error:(19, 10) overriding type GG in trait Impl with bounds <: scala.spike.TypeBoundInference.Example1.StaticGraph[scala.spike.TypeBoundInference.Example1.Impl1.DD]; type GG has incompatible type type GG = StaticGraph[Domain]

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

If you think the type constraint doesn't hold for some instances, could you give me counter example?

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

UPDATE2: turns out that according to the answer, this is true:

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

但这可能是错误的:

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

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

so in the context of DSL this may also be false:

I#GG <:< StaticGraph[I#GG](3)

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

But this is only part of the puzzle, to prove that it is type unsafe, we have to construct a counter example of DSL[I] that invalidates condition (3). So the old question remains: is it possible to construct a counter example?

推荐答案

确定已解决问题:

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]] {}
}

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

I can't believe I have to use higher kind for such banal matter :-<

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

Why it compiles? It decouples type constraint and delay it until it becomes necessary. (this is the only explanation I can think of)

这篇关于在scala中“不符合特征生成器的类型参数范围"是什么意思?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆