【问题标题】:How to call merge sort如何调用归并排序
【发布时间】:2014-05-04 07:47:49
【问题描述】:

以下代码基于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 以及为什么在调用过程中需要一个函数?

【问题讨论】:

    标签: scala


    【解决方案1】:

    在 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"))
    

    隐式参数

    正如链接中的文章提到的那样,您可能要使用多个参数列表的原因之一是隐式参数。

    当使用隐式参数并且你使用了implicit关键字时,它 适用于整个参数列表。因此,如果你只想要一些 参数是隐式的,你必须使用多个参数列表。

    让我们稍微修改一下你给我们的示例代码以引入一个新类型:

    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))
    

    【讨论】:

      【解决方案2】:
      def msort[T](less: (T, T) => Boolean)(xs: List[T]): List[T]
      

      这个函数有两个参数:一个函数less和一个列表xs

      如何调用 msort?

      您必须为两个参数提供值:msort(...)(...)

      为什么需要一个函数作为调用的一部分?

      因为参数less 声明为函数类型(T, T) =&gt; Boolean

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-01-11
        • 2014-12-15
        • 1970-01-01
        • 1970-01-01
        • 2015-06-10
        • 2016-03-11
        相关资源
        最近更新 更多