存在类型和类型成员的Scala类型推断

时间:2015-02-21 18:02:47

标签: scala type-inference existential-type type-members

以下代码无法编译:

trait A[F] {
  def find(x: Int): F
  def fill(f: F): Unit
}

object TestA {
  def test[T <: A[F] forSome { type F }](t: T) =
    t.fill(t.find(0))
}

它返回以下编译错误:

test.scala:8: error: type mismatch;
 found   : (some other)F(in type T)
 required: F(in type T)
    t.fill(t.find(0))
                 ^

但是,以下代码符合规定:

trait B[F] {
  type R = F
  def find(x: Int): R
  def fill(f: R): Unit
}

object TestB {
  def test[T <: B[F] forSome { type F }](t: T) =
    t.fill(t.find(0))
}

我在这里有两个问题:

  1. 我希望第一段代码能够编译。为什么不呢?

  2. 如果有一个很好的理由为什么第一段代码不能编译,我会期望第二段也不能编译,出于同样的原因。那么,它是如何成功编译的?

  3. 这些都是错误吗?

2 个答案:

答案 0 :(得分:3)

我不知道为什么编译器区分这两段代码。基本上,代码无法编译,因为find返回的类型和fill期望的类型不必相同F,至少find并且fill被调用了两个不同的对象。

您可以使用以下代码编写第一段代码:

def test[T <: A[F], F](t: T) =
  t.fill(t.find(0))

你可以使用第二段代码编译:

def test[T <: B[F] forSome { type F }](t: T, u: T) =
  t.fill(u.find(0))

这应该是一个评论而不是一个答案,但我还没有50个声誉。

答案 1 :(得分:2)

要了解正在发生的事情,让我们看一下TestA.testTestB.test的简单版本。

object TestA {
  def test1(a: A[String]) = {
    val s: String = a.find(0)
    a.fill(s)
  }
}

object TestB {
  def test1(b: B[String]) = {
    val r: b.R = b.find(0)
    b.fill(r)
  }
}

请注意中间值s的类型如何引用String,而中间值r的类型则不是。

object TestA {
  def test2(a: A[F] forSome {type F}) = {
    val s: F forSome {type F} = a.find(0)

    // type mismatch;
    //   found   : s.type (with underlying type F forSome { type F })
    //   required: F
    a.fill(s)
  }
}

object TestB {
  def test2(b: B[F] forSome {type F}) = {
    val r: b.R = b.find(0)
    b.fill(r)
  }
}

一旦我们抛出存在感,我们最终得到一个中间值s,其类型等同于Any,因此不是a.fill的有效输入。但是,r的中间类型仍为b.R,因此它仍然是b.fill的适当输入。其类型仍为b.R的原因是因为b.R未引用F,因此根据the simplification rules for existential typesb.R forSome {type F}相当于b.RInt forSome {type F}等同于Int的方式相同。

  

这些都是错误吗?

嗯,肯定有一个错误(从scalac 2.11.7开始),因为以下内容没有输入检查。

object TestB {
  def test3(b: B[F] forSome {type F}) = {
    val r: b.R forSome {type F} = b.find(0)

    // type mismatch;
    //   found   : F
    //   required: b.R
    //     (which expands to)  F
    b.fill(r)
  }
}

所以要么我认为b.R没有引用F,我认为b.R forSome {type F}不等同于b.RTestB.test不应该输入检查,但确实如此,或者b.R forSome {type F}b.R相同,在这种情况下我的TestB.test3应该输入检查,但不是。

我确信这个错误与后者有关,因为当存在量化与b.R无关时,甚至会发生错误,如下例所示。

object TestB {
  def test4(b: B[F] forSome {type F}) = {
    val r: b.R forSome {val x: Int} = b.find(0)

    // type mismatch;
    //   found   : F
    //   required: b.R
    //     (which expands to)  F
    b.fill(r)
  }
}