3

我试图在 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]

4

3 回答 3

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.minthat.min因为它想转换为this.minanOrdered[T]和. 最简单的答案是添加类型转换以强制到.that.minOrdered[U]this.minOrdered[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在使用 view bound 的每个上下文中获得不同的实现<% Ordered[Something],所以你真的应该寻找其他方法来确保你的排序是一致的。

于 2010-07-30T20:43:42.850 回答
2

<%我建议您手动添加隐式参数,而不是使用语法糖。它更加可控,当然更容易看到发生了什么:

def delMin[U >: T](implicit ord: U => Ordered[U]): SkewHeap[U] = left + right

在您的情况下使用<%运算符的问题是它绑定到T而不是U. 因此,它正在寻找 type 的函数T => Ordered[U]。事实上,你所有的方法都是这样做的,我怀疑这不是你想要的行为。

另外,关于习语的一个小注释:习惯上使用++运算符来连接两个集合,使用+运算符将​​单个值添加到现有集合(请参阅VectorArrayBuffer以及标准库中的几乎所有集合)。

于 2010-07-30T20:37:41.753 回答
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 ......)

于 2010-07-31T12:14:44.797 回答