Scala中的尾递归

时间:2017-10-12 07:11:43

标签: scala tail-recursion

我对scala尾递归有疑问。我写了一个简单的尾递归代码,它接受一个列表并创建一个偶数的新列表。但由于scala无法将元素追加到列表中,因此我的列表按降序排序。以下是代码

def listCreator(lists: List[Int]): List[Int] = {
    @tailrec
    def evenListCreator(lists: List[Int], accum: List[Int]): List[Int] = {
        lists match {
            case Nil => accum
            case x :: Nil if (isEven (x) == true) => x :: accum
            case x :: Nil if (isEven (x) == false) => accum
            case x :: tail if (isEven (x) == true) => evenListCreator(tail, x :: accum)
            case x :: tail if (isEven (x) == false) => evenListCreator(tail, accum)
        }
    }
    evenListCreator(lists, List()) 
}

我有以下问题

  1. 如何在此方法中添加反转列表的语句?

  2. 紧跟在方法调用之后的这一行evenListCreator(lists, List())是尾递归必需的吗?

3 个答案:

答案 0 :(得分:2)

你可以在返回之前撤消。

scala> def listCreator(lists: List[Int]): List[Int] = {
     |     @tailrec
     |     def evenListCreator(lists: List[Int], accum: List[Int]): List[Int] = {
     |         lists match {
     |             case Nil => accum
     |             case x :: Nil if (isEven (x) == true) => x :: accum
     |             case x :: Nil if (isEven (x) == false) => accum
     |             case x :: tail if (isEven (x) == true) => evenListCreator(tail, x :: accum)
     |             case x :: tail if (isEven (x) == false) => evenListCreator(tail, accum)
     |         }
     |     }
     |     evenListCreator(lists, List.empty[Int]).reverse 
     | }
listCreator: (lists: List[Int])List[Int]

scala> listCreator((1 to 10).toList)
res2: List[Int] = List(2, 4, 6, 8, 10)

scala>

您不需要立即跟随方法调用,但如果不这样做,则需要发送两个参数,一个是列表,第二个是空列表。因此我们只采用整数列表,以便正在使用的人也不必像发送空列表一样烦恼。

你也可以直接这样做

scala> val list = (1 to 10).toList
list: List[Int] = List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)

scala> list.map(_ * 2)
res8: List[Int] = List(2, 4, 6, 8, 10, 12, 14, 16, 18, 20)

scala> 

答案 1 :(得分:2)

  1. evenListCreator(lists, List()).reverseevenListCreator(lists.reverse, List()),但在您的情况下,第一种形式更好,因为在调用evenListCreator
  2. 后反向列表很可能会更短
  3. 此行:evenListCreator(lists, List())不遵循方法调用, 方法调用。没有它,没有任何事情会发生,因为你只定义你的尾递归函数(def evenListCreator)并在不调用它的情况下返回。
  4. 其他一些说明

    你有太多停止条件,这就足够了:

    @tailrec
    def evenListCreator(lists: List[Int], accum: List[Int]): List[Int] = {
      lists match {
        case Nil => accum
        case x :: tail if (isEven (x) == true) => evenListCreator(tail, x :: accum)
        case x :: tail if (isEven (x) == false) => evenListCreator(tail, accum)
      }
    }
    

    代码太冗长,我认为这样更好:

    @tailrec
    def evenListCreator(lists: List[Int], accum: List[Int]): List[Int] = {
      lists match {
        case Nil => accum
        case x :: tail if isEven (x) => evenListCreator(tail, x :: accum)
        case x :: tail if !isEven (x) => evenListCreator(tail, accum)
      }
    }
    

    你也可以这样调用递归函数:

    evenListCreator(lists, Nil)
    

答案 2 :(得分:2)

Q1。你可以在@Mahesh Chand Kandpal指出之前反转List,或者你可以使用追加方法accum :+ x来构建列表,而不是预先挂起(&#34) ; cons")方法,x :: accum

但是在List上,cons方法比append方法更有效,因此构建和反转通常更好。

Q2。不会。尾递归只是意味着在调用返回后没有其他操作等待。换句话说,return callMyself()是尾调用,但return callMyself() + 1不是。

P.S。我知道这只是一次学习练习,但是,真的......

def listCreator(ints: List[Int]): List[Int] = ints.filter(i => (i&1) < 1)