我在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的协方差规范。
但是,当单个对象实例完成工作时,我真的不想实例化新的空类。使用该对象似乎更清洁。
最后我的问题是:
答案 0 :(得分:0)
典型的类型擦除问题(Map的Key不变,Key的实际类型在提取器中被删除)。只需在提取器中使用类型定义:
case TrieNode(value, subTrie : Map[T, Trie[T, V]]) => new TrieNode(update(value), subTrie.updated(x, addWith(xs1, subTrie.getOrElse(x, EmptyTrie), update, default)))