斯卡拉的订购和没什么

时间:2013-09-01 14:36:43

标签: scala implicit

Scala的Ordered特征已被删除,因此我们必须使用Ordering。我试图重写我的BST类以使用Ordering并得到编译错误。任何人都可以解释我如何正确使用OrderingNothing。这是我的代码:

abstract sealed class Tree[+A: Ordering] {
  def value: A
  def left: Tree[A]
  def right: Tree[A]
  def isEmpty: Boolean

 /**
  * Time - O(1)
  * Space - O(1)
  */
 def mkTree(v: A, l: Tree[A] = Leaf, r: Tree[A] = Leaf): Tree[A] = 
   Branch(v, l, r)

 /**
  * Fails with message.
  */
 def fail(s: String): Nothing =
   throw new NoSuchElementException(s)
}

case object Leaf extends Tree[Nothing] {
  def value: Nothing = fail("Empty tree.")
  def left: Tree[Nothing] = fail("Empty tree.")
  def right: Tree[Nothing] = fail("Empty tree.")
  def isEmpty: Boolean = true
}

case class Branch[A: Ordering](value: A, left: Tree[A], right: Tree[A]) extends Tree[A] {
  def isEmpty: Boolean = false
}

编译时我得到以下内容:

Tree.scala:21: error: No implicit Ordering defined for Nothing.
case object Leaf extends Tree[Nothing] {
             ^
   one error found

我曾经把这个类写成abstract class Tree[+A <% Ordered[A]],但它运行良好。

2 个答案:

答案 0 :(得分:3)

我认为问题与Ordering和你设置树的方式不同。错误消息是不言自明的:你已经说过应该有一个类型参数的隐式排序,但是在Leaf的情况下,你已经给它了类型参数Nothing,这不是没有订购。

所以我要说每个Tree订购的要求是不正确的。您需要做的就是从第一行中删除: Ordering,因为您已经在Branch中包含了该要求,它确实有意义。

您的mkTree方法需要(implicit ord: Ordering[A])参数,但我看不出此方法的用途 - 它看起来像属于伴随对象的工厂方法(它所做的,因为你只是按照Branch对象) - 所以我会删除它。

答案 1 :(得分:2)

Luigi是正确的,对于Tree类型,顺序没有意义。但是,如果使用Algebraic Data Type,这个要求会更加明显,设计会更清晰。它们使用类层次结构作为接口的一部分,因此它们比面向对象更具功能性(如Scala中的Option和List)。

然后直接使用case类来实例化它们(不需要mkTree函数),并使用模式匹配来检索它们。

例如:

sealed trait Tree[+A] {
  def isEmpty: Boolean
}

case object Leaf extends Tree[Nothing] {
  def isEmpty: Boolean = true
}

case class Branch[+A: Ordering](value: A, left: Tree[A] = Leaf, right: Tree[A] = Leaf) extends Tree[A] {
  def isEmpty: Boolean = false
}

def depthFirstSearch[A: Ordering](tree: Tree[A], expected: A): Option[Branch[A]] = {
  import Ordering.Implicits._

  tree match {
    case t @ Branch(value, _, _) if value == expected => Some(t)
    case Branch(value, left, _) if value > expected => depthFirstSearch(left, expected)
    case Branch(value, _, right) if value < expected => depthFirstSearch(right, expected)
    case _ => None
  }
}