Scala 2.10的ADT类型推断失败——从2.9.3开始回归



我在尝试在Scala 2.10中使用简单的ADT时遇到了一个奇怪的问题。下面的程序显示了这个问题:

sealed trait Trie[+T, +V]
case object EmptyTrie extends Trie[Nothing, Nothing]
case class TrieNode[T, V](data: V, subTrie: Map[T, Trie[T, V]]) extends Trie[T, V]
case class TrieLeaf[T, V](data: V) extends Trie[T, V]
object Trie {
  def emptyTrie[T, V](): Trie[T, V] = EmptyTrie
  def addWith[T, V](xs: List[T], trie: Trie[T, V], update: (V => V), default: V): Trie[T, V] =
    xs match {
      case Nil => trie match {
        case EmptyTrie                => new TrieLeaf(default)
        case TrieNode(value, subTrie) => new TrieNode(update(value), subTrie)
        case TrieLeaf(value)          => new TrieLeaf(update(value))
      }
      case x :: xs1 => trie match {
        case EmptyTrie                => new TrieNode(default, Map(x -> addWith(xs1, EmptyTrie, update, default)))
        case TrieNode(value, subTrie) => new TrieNode(update(value), subTrie.updated(x, addWith(xs1, subTrie.getOrElse(x, EmptyTrie), update, default)))
        case TrieLeaf(value)          => new TrieNode(update(value), Map(x -> addWith(xs1, EmptyTrie, update, default)))
      }
    }
}

用Scala 2.10编译这段代码。X会导致以下错误:

[error] /tmp/rendererkH7rTCTbYi/src/main/scala/test.scala:22: type mismatch;
[error]  found   : x.type (with underlying type T)
[error]  required: ?T4 where type ?T4 <: T (this is a GADT skolem)
[error]         case TrieNode(value, subTrie) => new TrieNode(update(value), subTrie.updated(x, addWith(xs1, subTrie.getOrElse(x, EmptyTrie), update, default)))
[error]                                                                                      ^
[error] /tmp/rendererkH7rTCTbYi/src/main/scala/test.scala:22: type mismatch;
[error]  found   : x.type (with underlying type T)
[error]  required: ?T4 where type ?T4 <: T (this is a GADT skolem)
[error]         case TrieNode(value, subTrie) => new TrieNode(update(value), subTrie.updated(x, addWith(xs1, subTrie.getOrElse(x, EmptyTrie), update, default)))
[error]                                                                                                                        ^

同样的代码用Scala 2.9.3编译成功,程序运行正常。

我通过将EmptyTrie定义更改为:

来解决问题
case class EmptyTrie[T, V]() extends Trie[T, V]

,在性状定义上去掉T和V上的协方差说明。

然而,当单个对象实例可以完成工作时,我真的不喜欢实例化新的空类。使用对象看起来干净多了。

最后我的问题是:

  • 这是一个回归在scala编译器?
  • 是否可以添加一些类型提示来帮助编译器(我在这方面的所有尝试)居然没有)?

典型的类型擦除问题(Map是键不变的,在提取器中擦除键的实类型)。在extractor中使用类型定义:

case TrieNode(value, subTrie : Map[T, Trie[T, V]]) => new TrieNode(update(value), subTrie.updated(x, addWith(xs1, subTrie.getOrElse(x, EmptyTrie), update, default)))

最新更新