Annotation.tailrec在scala中抛出编译错误

时间:2016-07-23 19:17:47

标签: scala

我在scala 2.11.8版本中编写合并排序程序。

以下是我的计划 -

 object ListMergeSort {

      def main(args:Array[String]): Unit ={
        val list:List[Int]= List(1,5,7,2,9,3,8,6,4)
        println(list)

        println(sort(list))
      }


      def sort(l:List[Int]):List[Int]= {
        l match{
          case Nil => l
          case h::Nil => l
          case _ =>
            val (l1,l2) = l splitAt(l.length/2)
            listMergeSort(sort(l1),sort(l2))
        }
      }

      //@annotation.tailrec
      def listMergeSort(l1:List[Int],l2:List[Int]):List[Int]={
        (l1,l2) match{
          case (Nil,l2) => l2
          case (l1,Nil) => l1
          case (h1::t1, h2::t2) => if (h1<h2) h1::listMergeSort(t1,l2) else h2::listMergeSort(l1,t2)
        }
      }
    }

上述程序在技术上工作正常,输出为我提供了排序列表。

我想将listMergeSort函数注释为尾递归,但编译器给出错误“递归调用不在尾部位置”。

enter image description here

    import scala.util.Random        
    object test {

      def msort[T <% Ordered[T]](xs: List[T]): List[T] = {

        @annotation.tailrec
        def merge(res: List[T], xs: List[T], ys: List[T]): List[T] = (xs, ys) match {
          case (_, Nil) => res.reverse ::: xs
          case (Nil, _) => res.reverse ::: ys
          case (x :: xs1, y :: ys1) =>
            if (x < y) merge(x :: res, xs1, ys)
            else merge(y :: res, xs, ys1)
        }

        val n = xs.length / 2
        if (n == 0) xs
        else {
          val (ys, zs) = xs splitAt n
          merge(Nil, msort(ys), msort(zs))
        }
      }

      def main(args: Array[String]) {
        val list = Seq.fill(10)(Random.nextInt(500)).toList
        println(list)
        println(msort(list))
      }
    }

上述程序也有类似的合并功能,但@ annotation.tailrec没有抛出任何错误。

任何人都可以帮助我的程序中出现错误的根本原因吗?

1 个答案:

答案 0 :(得分:4)

编译器告诉你要告诉你的一切。

这一行..

if (h1<h2) h1::listMergeSort(t1,l2) else h2::listMergeSort(l1,t2)

...不是尾递归,因为在 listMergeSort()之后返回还有更多工作要做,即预先挂起h1h2元素。

另一方面,这一行是尾递归...

if (x < y) merge(x :: res, xs1, ys) else merge(y :: res, xs, ys1)

...因为在merge返回后没有其他任何事情可做,只需返回merge()返回的内容。