scala存在性与f有界多态的奇怪编译错误

时间:2017-05-05 14:21:02

标签: scala existential-type f-bounded-polymorphism

为什么以下代码无法编译?

  trait B[T <: B[T]]
  case class A[T <: B[T]](t: T)

  class C() extends B[C]
  val c: C = new C()

  val r2: A[_]         = A(c)     //compiles
  val r3: A[_]         = A(c)     //compiles fine
  val r4: A[_]         = r3       //compiles fine
  val r5: (A[_])       = (r3)     //compiles fine
  val r6: (A[_], A[_]) = (r3, r3) // does not compile, strange

它给出了:

Error:(68, 22) type arguments [_$7] do not conform to class A's type parameter bounds [T <: _experiment.akka_persistence.Test2.B[T]]
  val r6:(A[_],A[_])=(r3,r3)

编辑:

以下是相关的自包含代码段:

  import scala.language.existentials


  trait B[T <: B[T]]
  case class A[T <: B[T]](t: T)

  class C() extends B[C]
  val c: C = new C()
  type SomeB = T forSome { type T <: B[T] }
  val r3: A[_<:SomeB]         = A(c)     //compiles fine
  val r4: A[C]         = A(c)     //compiles fine
  val r5: (A[_<:SomeB])       = (r3)     //compiles fine
  val r6:((_<:SomeB),((_<:SomeB))) = (c,c)  // compiles fine
  val r7:(A[_<:SomeB],((_<:SomeB))) = (A(c),c)  // compiles fine
  val r8:(A[_<:SomeB],(A[_<:SomeB])) = (A(c),A(c))  // compiles fine
  val r10:(A[_<:SomeB],(A[_<:SomeB])) = (A(c),r4)  // compiles fine
  val r9:(A[_<:SomeB],(A[_<:SomeB])) = (A(c),r3)  // does not compile
  • 似乎r4的类型必须为A[C],然后才会r10进行编译。
  • 因此,这表明A[_<:SomeB]的{​​{1}}不够具体。但为什么不呢?
  • 为什么r3 A[_<:SomeB]足够val r5: (A[_<:SomeB]) = (r3)r9呢?

1 个答案:

答案 0 :(得分:1)

首先,您的r4r5实际上是等效的。要声明类型Tuple1的val,您需要明确:

val r5: Tuple1[A[_]] = Tuple1(r3)

然后你会发现它也会因同样的错误而失败。

在REPL中:

scala> Tuple1(r3)
<console>:24: warning: inferred existential type (A[_$1],) forSome { type _$1 }, which cannot be expressed by wildcards,  should be enabled
by making the implicit value scala.language.existentials visible.
This can be achieved by adding the import clause 'import scala.language.existentials'
or by setting the compiler option -language:existentials.
See the Scaladoc for value scala.language.existentials for a discussion
why the feature should be explicitly enabled.
       Tuple1(r3)
             ^
<console>:24: error: type arguments [_$1] do not conform to class A's type parameter bounds [T <: B[T]]
       Tuple1(r3)
       ^

您看到给定的存在类型r3编译器将元组推断为(A[_$1],) forSome { type _$1 }

这种情况确实类似于@jhegedus(Existential types for F-Bounded Polymorphic types and non-generic subtypes?)中的情况,同样的解决方案适用,即通过明确指定Tuple1的类型参数给编译器一些帮助:

val r5 = Tuple1[A[_]](r3)

或者给r3更具体的类型:

val r3: A[C] = A(c)
val r5: Tuple1[A[_]] = Tuple1(r3)

r6 / Tuple2

也是如此