在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的新手,所以我可能完全误解了一些东西,但我并没有真正解决这些错误。
答案 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'))
最后的话
我真的很高兴我找不到一个很好的方式来讨论。也许有更多洞察力的人可以提供更好的答案。