以下代码基于Merge sort from "Programming Scala" causes stack overflow
def msort[T](less: (T, T) => Boolean)(xs: List[T]): List[T] = {
def merge(xs: List[T], ys: List[T], acc: List[T]): List[T] =
(xs, ys) match {
case (Nil, _) => ys.reverse ::: acc
case (_, Nil) => xs.reverse ::: acc
case (x :: xs1, y :: ys1) =>
if (less(x, y)) merge(xs1, ys, x :: acc)
else merge(xs, ys1, y :: acc)
}
val n = xs.length / 2
if (n == 0) xs
else {
val (ys, zs) = xs splitAt n
merge(msort(less)(ys), msort(less)(zs), Nil).reverse
}
}
当我尝试使用:
调用msort时 val l = List(5, 2, 4, 6, 1, 3)
msort[Int](l)
我收到错误:
Multiple markers at this line - type mismatch; found : List[Int] required: (Int, Int) => Boolean - type mismatch;
found : List[Int] required: (Int, Int) => Boolean - missing arguments for method msort in object mergesort; follow
this method with `_' if you want to treat it as a partially applied function
如何调用msort&为什么函数需要作为调用的一部分?
答案 0 :(得分:4)
在Scala中,可以Multiple Parameters Lists。您的调用只传递一个参数。
该方法声明为def msort[T](less: (T, T) => Boolean)(xs: List[T]): List[T]
,因此第一个参数的类型为(T, T) => Boolean
,该函数采用类型T
的两个参数并返回Boolean
值。你传递了List[Int]
,这让Scala抱怨。
你为什么要这样做,你可能会问。好吧,请考虑以下示例。
val stringSorter = msort[String]((a, b) => a.compareTo(b) < 0) _
// stringSorter: List[String] => List[String] = <function1>
val integerSorter = msort[Int]((a, b) => a < b) _
// integerSorter: List[Int] => List[Int] = <function1>
这两个调用创建了两个只接受一个参数的新函数 - 您要排序的列表。您不必告诉它如何比较元素,因为您已经这样做了。请注意,您可以使用不同的列表作为参数调用相同的函数。
integerSorter(List(2, 3, 1))
// res0: List[Int] = List(1, 2, 3)
integerSorter(List(2, 4, 1))
// res1: List[Int] = List(1, 2, 4)
stringSorter(List("b", "a", "c"))
res3: List[String] = List(a, b, c)
另请注意,新创建的函数是类型安全的,以下代码将失败:
integerSorter(List("b", "a", "c"))
<console>:10: error: type mismatch;
found : String("b")
required: Int
integerSorter(List("b", "a", "c"))
正如链接中的文章所提到的,您可能想要使用多个参数列表的原因之一是隐式参数。
使用隐式参数时,您使用隐式关键字 适用于整个参数列表。因此,如果你只想要一些 要隐式的参数,必须使用多个参数列表。
让我们修改你给我们一些介绍新类型的示例代码:
trait Comparator[T] {
def less(a: T, b: T): Boolean
}
然后让我们交换参数列表,并将implicit
关键字添加到第二个关键字,现在它变为:
def msort[T](xs: List[T])(implicit c: Comparator[T]): List[T] = {
def merge(xs: List[T], ys: List[T], acc: List[T]): List[T] =
(xs, ys) match {
case (Nil, _) => ys.reverse ::: acc
case (_, Nil) => xs.reverse ::: acc
case (x :: xs1, y :: ys1) =>
if (c.less(x, y)) merge(xs1, ys, x :: acc)
else merge(xs, ys1, y :: acc)
}
val n = xs.length / 2
if (n == 0) xs
else {
val (ys, zs) = xs splitAt n
merge(msort(ys)(c), msort(zs)(c), Nil).reverse
}
}
现在你可以声明一个隐含的对象,这个对象将在你不提供时使用,例如
implicit val intComparator = new Comparator[Int] { def less(a: Int, b: Int) = a < b }
msort(List(5, 3, 1, 3))
// res8: List[Int] = List(1, 3, 3, 5)
虽然这看起来似乎不太吸引人,但在设计API时会给你额外的灵活性。我们假设我们有一个名为CustomType
的类型。它可以在随播对象中声明隐式,它将由编译器“自动”解析。
case class CustomType(ordinal: Int, name: String)
object CustomType {
implicit val customTypeComparator = new Comparator[CustomType] {
def less(a: CustomType, b: CustomType) = a.ordinal < b.ordinal
}
}
msort(List(CustomType(2, "Second"), CustomType(1, "First")))
// res11: List[CustomType] = List(CustomType(1,First), CustomType(2,Second))
答案 1 :(得分:1)
def msort[T](less: (T, T) => Boolean)(xs: List[T]): List[T]
此函数有两个参数:函数less
和列表xs
。
如何调用msort?
您必须为两个参数提供值:msort(...)(...)
。
为什么函数需要作为调用的一部分?
因为参数less
是用函数类型(T, T) => Boolean
声明的。