我正在尝试在Scala中实现在类型T
上参数化的通用数据类型,该类型应为Ordered[T]
。具体来说,它是Sleator&amp ;;的持久版本。 Tarjan的skew heap优先级队列。在根据解释here和Odersky-Spoon-Venners添加了许多复杂的类型参数声明之后,在我测试/调试实际功能之前,我遇到了一个编译器错误。
以下是我的代码的简化版本。
abstract class SkewHeap[+T] {
// merge two heaps
def +[U >: T <% Ordered[U]](x : SkewHeap[U]) : SkewHeap[U]
// remove least element, return new heap
def delMin[U >: T <% Ordered[U]] : SkewHeap[U]
def isEmpty : Boolean
def min : T
def left : SkewHeap[T]
def right : SkewHeap[T]
}
case object Leaf extends SkewHeap[Nothing] {
def +[U <% Ordered[U]](that : SkewHeap[U]) = that
def isEmpty = true
}
case class Node[+T](left : SkewHeap[T],
min : T,
right : SkewHeap[T]) extends SkewHeap[T] {
def +[U >: T <% Ordered[U]](that : SkewHeap[U]) : SkewHeap[U] =
that match {
case Leaf => this
case Node(l,y,r) => if (this.min < that.min)
Node(this.right + that, this.min, this.left)
else
Node(this + that.right, that.min, that.left)
}
def delMin[U >: T <% Ordered[U]] : SkewHeap[U] = left + right
def isEmpty = false
}
这会出现以下错误:
skew.scala:28: error: no implicit argument matching parameter type (T) => Ordered[T] was found.
def delMin[U >: T <% Ordered[U]] : SkewHeap[U] = left + right
我尝试了delMin
声明的几种变体,但无济于事。我想我理解这个问题(方法+
想要一个订购保证),但我应该把它放在哪里?是否可以将delMin
声明为返回SkewHeap[T]
而不是SkewHeap[U]
?
答案 0 :(得分:3)
abstract class SkewHeap[+T <% Ordered[T]] {
// merge two heaps
def +[U >: T <% Ordered[U]](x : SkewHeap[U]) : SkewHeap[U]
// remove least element, return new heap
def delMin : SkewHeap[T]
def isEmpty : Boolean
def min : T
def left : SkewHeap[T]
def right : SkewHeap[T]
}
case object Leaf extends SkewHeap[Nothing] {
def +[U <% Ordered[U]](that : SkewHeap[U]) = that
def isEmpty = true
def min = throw new RuntimeException
def left = throw new RuntimeException
def right = throw new RuntimeException
def delMin = throw new RuntimeException
}
Scala不确定如何将this.min
与that.min
进行比较,因为它希望将this.min
转换为Ordered[T]
而将that.min
转换为Ordered[U]
1}}。最简单的答案是添加类型转换以强制this.min
到Ordered[U]
。
case class Node[+T <% Ordered[T]](left : SkewHeap[T],
min : T,
right : SkewHeap[T]) extends SkewHeap[T] {
def +[U >: T <% Ordered[U]](that : SkewHeap[U]) : SkewHeap[U] =
that match {
case Leaf => this
case Node(l,y,r) => if ((this.min:Ordered[U]) < that.min)
Node(this.right + that, this.min, this.left)
else
Node(this + that.right, that.min, that.left)
}
def delMin : SkewHeap[T] = left + right
def isEmpty = false
}
但是你对所有这些含义都有一个很大的问题,那就是你可以在使用视图绑定Ordered
的每个上下文中获得不同的<% Ordered[Something]
实现,所以你应该真的寻找其他方法来确保您的订购是一致的。
答案 1 :(得分:2)
我建议你手动添加隐含参数,而不是使用<%
句法糖。它受到更多控制,当然更容易看到发生了什么:
def delMin[U >: T](implicit ord: U => Ordered[U]): SkewHeap[U] = left + right
在您的案例中使用<%
运算符的问题是它绑定到T
而不是U
。因此,它正在寻找类型T => Ordered[U]
的函数。事实上,你所有的方法都是这样做的,我怀疑这不是你想要的行为。
此外,关于习语的小注:习惯上使用++
运算符连接两个集合,而+
运算符用于向现有集合添加单个值(请参阅{{1 },Vector
,以及标准库中的几乎任何集合。
答案 2 :(得分:0)
除了其他建议之外,您可以考虑从Ordered切换到隐式参数Ordering [T],它更容易控制并为您提供更大的灵活性。
[编辑] 一个非常简单的例子:
class Foo[T](val t:T)(implicit val ord: Ordering[T]) {
def min(that:Foo[T]) = if (ord.compare(this.t, that.t) < 0) this else that
}
在此之后,您可以将Foo用于所有具有排序的类型。当然你可以自己制作一个:
implicit object barOrdering extends Ordering[Bar] {...}
在此之后,您可以创建Foo[Bar]
。
(很抱歉这个非常基本的例子,我的电脑坏了,我没有IDE可用......)