为什么这个scala连接函数不是尾递归的?

时间:2016-09-20 21:20:54

标签: scala recursion tail-recursion

我试图编写一个函数repeat(s:String,n:Int),它将连接字符串sn次并返回它,但由于某种原因我得不到正确的结果并且收到错误它不是尾递归的,而且我在逻辑上难以理解为什么这不会是尾递归的。

在连接完成之前是否必须处理递归?我该如何解决这个问题?使递归重复(s + s,n-1)不会起作用,因为它会递归太多次,但我不知道还有什么其他方法可以做到。

/**
 * Returns concatenated string s, concatenated n times
 */
@annotation.tailrec
def repeat(s: String, n: Int): String = n match {
  case zero if (n == 0) => "" // zero repeats 
  case emptyString if (s == "") => throw new IllegalArgumentException("You must input a string") //no string exception
  case fail if (n < 0) => throw new IllegalArgumentException("Cannot use a negative number") //throw exception
  case last if (n == 1) => s
  case concatenate => s + repeat(s, n-1) //tail-end recursion & concat. 
}

ps:我这样做主要是为了练习递归,而不是为了获得优化的代码

2 个答案:

答案 0 :(得分:3)

s + repeat(s, n-1)使你的函数答案依赖于函数的其他调用,如果你想要尾递归,你应该避免不同调用之间的依赖。

例如:

 def repeat(s: String, n: Int): String = {

    @annotation.tailrec
    def repeatIter(buffer: String, n: Int): String = {
      n match {
        case 0 => buffer
        case _ => repeatIter(buffer + s, n - 1)
      }
    }

    if (s.isEmpty || n < 0) throw new IllegalArgumentException("ERROR")
    else repeatIter("", n)
  }

答案 1 :(得分:1)

在尾递归的情况下,当前结果不应该依赖于延迟的先前调用堆栈计算

对您的功能def repeat(s: String, result: String, n: Int): String进行以下更改。 通知函数参数

@annotation.tailrec
    def repeat(s: String, result: String, n: Int): String = n match {
      case zero if (n == 0) => "" // zero repeats 
      case emptyString if (s == "") => throw new IllegalArgumentException("You must input a string") //no string exception
      case fail if (n < 0) => throw new IllegalArgumentException("Cannot use a negative number") //throw exception
      case last if (n == 1) => result
      case concatenate => repeat(s, s + result, n-1) //tail-end recursion & concat. 
    }

<强>用法

scala> repeat("apple", "apple", 2)
res3: String = appleapple

使用helper内部函数

实现更清晰的方法
def repeat(s: String, n: Int): String = {
      @annotation.tailrec
      def helper(result: String, n: Int): String = n match {
        case zero if (n == 0) => "" // zero repeats
        case emptyString if (s == "") => throw new IllegalArgumentException("You must input a string") //no string exception
        case fail if (n < 0) => throw new IllegalArgumentException("Cannot use a negative number") //throw exception
        case last if (n == 1) => result
        case concatenate => helper(s + result, n - 1) //tail-end recursion & concat.
      }
      helper(s, n)
    }

<强>用法

scala> repeat("apple", 1)
res6: String = apple

scala> repeat("apple", 2)
res7: String = appleapple