Search code examples
scalarecursiontail-recursion

Tail Recursive Factorial Function in Scala


I thought that the factorial function below is tail-recursive, when I tested it, works fine till 10 and becomes weird at 20 (negative output) and when I insert 100, the answer is 0:

def factorial(n: Int, m: Int = 1): Int = 
    if (n == 0) m else fact(n-1, m * n)

but when I put @tailrec above it, I get the following error:

error: not found: type tailrec

I can't understand why this function is not tail-recursive. A stack-recursive factorial function is:

def factorial(n: Int): Int = 
    if (n == 0) 1 else n * factorial(n-1)

The above function modifies the external expression after else at each recursive call. Whereas the first function only modifies what's inside the function. Now, to make a recursive factorial function, what they do is create a function inside a function. But, can a recursive factorial function be created just with the body of the first function in this question?

Also, is the "m" in the former function a variable?

Edit: Now after doing what is suggested in the answer, I get the error message if a function is not tail-recursive:

error: could not optimize @tailrec annotated method factorial: it contains a recursive call not in tail position

Solution

  • Several things:

    • You have to import @tailrec annotation to be able to use it without a full name:

      import scala.annotation.tailrec
      
      @tailrec
      def factorial(n: Int, m: Int = 1): Int = 
        if (n == 0) m else fact(n-1, m * n)
      

      Without @tailrec scalac will still be able to do tail recursion optimization, it just won't enforce it (it won't fail compilation if TRO won't be possible).

    • Integer has a limited capacity - it's 32-bit 2-compliment and everything bigger than 2^31-1 overflows and goes into negative numbers

    So you have to import annotation or use a full name (@scala.annotation.tailrec) AND replace Int with something bigger (Long is also not enough, more like BigInteger).