Isn't that code in tail recursive style?

前端 未结 2 1995
萌比男神i
萌比男神i 2021-02-05 00:01

I\'m kinda new to Scala trying it out while reading Beggining Scala by David Pollack. He defines a simple recursive function that loads all strings from the file:



        
相关标签:
2条回答
  • 2021-02-05 00:28

    Scala can only optimise this if the last call is a call to the method itself.

    Well, the last call is not to allStrings, it's actually to the :: (cons) method.

    A way to make this tail recursive is to add an accumulator parameter, for example:

    def allStrings(expr: => String, acc: List[String] = Nil): List[String] =
      expr match {
        case null => acc
        case w => allStrings(expr, w :: acc)
      }
    

    To prevent the accumulator leaking into the API, you can define the tail recursive method as a nested method:

    def allStrings(expr: => String) = {
      def iter(expr: => String, acc: List[String]): List[String] =
        expr match {
          case null => acc
          case w => iter(expr, w :: acc)
        }
      iter(expr, Nil)
    }
    
    0 讨论(0)
  • 2021-02-05 00:31

    It's not tail recursive (and can't ever be) because the final operation is not a recursive call to allStrings, it's a call to the :: method.

    The safest way to resolve this is with a nested method that uses an accumulator:

    def allStrings(expr: => String) = {
      @tailrec
      def inner(expr: => String, acc: List[String]): List[String] = expr match {
        case null => acc
        case w => inner(expr, w :: acc)
      }
      inner(expr, Nil)
    }
    

    In this particular case, you could also lift the accumulator to a parameter on allStrings, give it a default value of Nil, and avoid the need for an inner method. But that's not always possible, and it can't be called nicely from Java code if you're concerned about interop.

    0 讨论(0)
提交回复
热议问题