如何使curried合并排序适当通用

时间:2014-09-01 00:44:30

标签: scala

Scala by Example中,有一个合并排序的实现,它使比较函数在内部使用:

def mergeSort[T <% Ordered[T]](less: (T, T) => Boolean)(list: List[T]): List[T] = {

  def merge(xs: List[T], ys: List[T]): List[T] = {
    if (xs.isEmpty) ys
    else if (ys.isEmpty) xs
    else if (less(xs.head, ys.head)) xs.head :: merge(xs.tail, ys)
    else ys.head :: merge(ys.tail, xs)
  }

  val n = list.length / 2
  if (n == 0) list
  else merge(mergeSort(less)(list.take(n)), mergeSort(less)(list.drop(n)))
}

我可以打电话给这个,如书中所示:

mergeSort((x: Int, y: Int) => x < y)(List(3,2,1))

冷却。但我喜欢的是:

def orderedLess[T <% Ordered[T]](x: T, y: T) = x < y
def basicMergeSort = mergeSort(orderedLess)_

编译器并不喜欢这样。

Lists.scala:62: error: No implicit view available from T => Ordered[T].
  def basicMergeSort = mergeSort(orderedLess)_
                                 ^
Lists.scala:62: error: No implicit view available from Any => Ordered[Any].
  def basicMergeSort = mergeSort(orderedLess)_
                                ^

解决这个问题的方法似乎是在那里抛出一个类型参数。任

def basicMergeSort = mergeSort[Int](orderedLess)_

def basicMergeSort = mergeSort(orderedLess[Int])_

将编译,但我希望能够传递任何类型的Ordered类型。我究竟做错了什么?我是Scala的新手,所以我可能完全误解了一些东西,但我并没有真正解决这些错误。

1 个答案:

答案 0 :(得分:4)

首先关闭:

您永远不会看到[T <% Ordered[T]](less: (T, T) => Boolean)之类的内容。 您希望用户指定比较函数,或者您希望使用隐式排序,以便可以访问默认比较函数。你可以在std库中看到这个。

 def sortWith(lt: (A, A) => Boolean): List[A] 
 def sorted[B >: A](implicit ord: math.Ordering[B]): List[A]

所以我会保留签名,就像你的链接一样。

def mergeSort[T](less: (T, T) => Boolean)(list: List[T]): List[T]

现在回到问题。

解决方案1 ​​

这与您的方法类似。编译器似乎需要有关类型的其他信息。

def orderedLess[T <% Ordered[T]](x: T, y: T) = x < y
def basicMergeSort[T <% Ordered[T]] = mergeSort[T](orderedLess)_ 

您也可以像这样合并:

def basicMergeSort[T <% Ordered[T]] = mergeSort((x: T, y: T) => x < y) _

然而,在调用它时会出现“坏”的东西。它只是那样。

basicMergeSort[Char].apply(List('a','d','c'))

编译器不会为您推断出类型,也不能使用apply的糖语法。 def basicMergeSort[T <% Ordered[T]]将被翻译为类似def basicMergeSort[T](implicit ord: T => Ordered[T])的内容,当尝试调用basicMergeSort[Char](List('a','d','c'))时,它会将列表视为隐式参数,这当然无效。

解决方案2

这是一个没有curry的解决方案。它基本上是一种方法,只接受具有隐式排序的元素的列表,并使用具有所需函数的mergeSort

def basicMergeSort[T <% Ordered[T]](list: List[T]) = mergeSort((x: T, y: T) => x < y)(list)

这里的一切都是推断的,很好。

basicMergeSort(List('a','d','c'))

最后的话

我真的很高兴我找不到一个很好的方式来讨论。也许有更多洞察力的人可以提供更好的答案。