通用优先级队列中的协变和逆变类型
我正在尝试在 Scala 中实现一个在类型 T
上参数化的通用数据类型,该类型应该是 Ordered[T]
。具体来说,它是 Sleator & 的持久版本。 Tarjan 的倾斜堆优先级队列。根据此处的解释添加大量复杂的类型参数声明后在 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]
?
I'm trying to implement in Scala a generic data type parameterized on a type T
, which should be Ordered[T]
. Specifically, it's a persistent version of Sleator & Tarjan's skew heap priority queues. After adding lots of complicated type parameter declarations based on the explanation here and in Odersky-Spoon-Venners, I'm down to one compiler error before I can test/debug the actual functionality.
Below is a simplified version of my code.
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
}
This gives the following error:
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
I've tried several variants of the declaration of delMin
, but to no avail. I think I understand the problem (method +
wants an ordering guarantee), but where should I put this? And is there a way to declare delMin
as returning SkewHeap[T]
instead of SkewHeap[U]
?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
Scala 不确定如何比较
this.min
与that.min
,因为它想要将this.min
转换为Ordered[T]
和that.min
为Ordered[U]
。最简单的答案是添加类型转换以将this.min
强制转换为Ordered[U]
。但是,所有这些隐式都存在一个大问题,这个问题是,在使用视图绑定
<% Ordered[Something] 的每个上下文中,您都可能会得到不同的
,所以你真的应该寻找其他方法来确保你的排序是一致的。Ordered
实现。Scala isn't sure how to compare
this.min
withthat.min
, becuase it wants to convertthis.min
to anOrdered[T]
andthat.min
to anOrdered[U]
. The simplest answer is to add a type conversion to forcethis.min
to anOrdered[U]
.But you have a big problem with all of these implicits, and that problem is that you could get a different
Ordered
implementation in every context where you use the view bound<% Ordered[Something]
, so you should really look for some other way of making sure your ordering is consistent.我建议您手动添加隐式参数,而不是使用
<%
语法糖。它更受控制,当然更容易看到发生了什么:在您的情况下使用
<%
运算符的问题是它绑定到T
而不是U。因此,它正在寻找
T => 类型的函数。已订购[U]
。事实上,你所有的方法都在这样做,我怀疑这不是你想要的行为。另外,关于习语的一个小注意事项:习惯上使用
++
运算符来连接两个集合,并使用+
运算符将单个值添加到现有集合(请参阅Vector
、ArrayBuffer
以及标准库中的几乎所有集合)。Rather than using the
<%
syntactic sugar, I suggest that you manually add the implicit parameter. It's a lot more controlled, and certainly easier to see what's going on:The problem with using the
<%
operator in your case is it binds toT
rather thanU
. Thus, it was looking for a function of typeT => Ordered[U]
. In fact, all of your methods are doing this, and I suspect that's not the behavior you wanted.Also, a minor note on idioms: it is customary to use the
++
operator for concatenating two collections, and the+
operator for adding a single value to an existing collection (seeVector
,ArrayBuffer
, and pretty much any collection in the standard library).除了其他建议之外,您还可以考虑从 Ordered 切换到隐式参数 Ordering[T],这更容易控制并为您提供更大的灵活性。
[编辑]
一个非常简单的示例:
在此之后,您可以将 Foo 用于所有具有排序的类型。当然,您可以自己制作一个:
在此之后,您可以创建一个
Foo[Bar]
。(对于这个非常基本的例子,我很抱歉,我的电脑坏了,而且我没有可用的 IDE...)
Additional to the other suggestions, you may consider to switch from Ordered to an implicit parameter Ordering[T], which is much easier to control and gives you more flexibility.
[Edit]
A very simple example:
After this you can use Foo for all types that have an ordering. Of course you can make one yourself:
After this, you could create a
Foo[Bar]
.(Sorry for the very basic example, my PC broke down and I have no IDE available...)