7

I'm trying to write a tail recursive function in the below way, but the compiler is throwing an error:

Too many arguments for method apply: (v1: Int)Int in trait Function1 else factorial(x-1, x*acc)

I had tried replacing Function1 with Function2 and gave Function2[Int, Int, Int] = new Function2[Int, Int, Int]

But it still threw me the same error. Can someone point out where i'm going wrong?

import scala.annotation.tailrec
var factorial: Function1[Int, Int] = new Function1[Int, Int] {
    @tailrec override def apply (x:Int, acc:Int=1): Int = {
        if (x<=1) acc
        else factorial(x-1, x*acc)
    }
}

factorial(5)
SCouto
  • 7,808
  • 5
  • 32
  • 49
Vasu
  • 85
  • 1
  • 5

5 Answers5

11

You apply inside Function1 must take only one param, when you are passing two.

You can rewrite it as follows:

var factorial: Function1[Int, Int] = new Function1[Int, Int] {
  def apply (x:Int): Int = {
    @tailrec def loop(x: Int, acc: Int = 1): Int = {
      if (x<=1) acc
      else loop(x-1, x*acc)
    }
    loop(x)
  }
}
Yevhenii Popadiuk
  • 1,024
  • 7
  • 18
  • 1
    You can read a bit more [here](https://stackoverflow.com/questions/25234682/in-scala-can-you-make-an-anonymous-function-have-a-default-argument) about a reason why anonymous function doesn't support a default argument. – Yevhenii Popadiuk Dec 27 '17 at 14:41
2

Function1 represents a function with a single parameter (the second one is for the output)

So you need to define your apply method with a single parameter, and then, inside it, do the recursion using a nested function:

  import scala.annotation.tailrec
  var factorial: Function1[Int, Int] = new Function1[Int, Int] {

    override def apply(x: Int): Int = {
      @tailrec
      def go (x: Int, acc: Int = 1) : Int = {
        if (x<=1) acc
        else go(x-1, x*acc)
      }
      go(x)
    }
  }
  factorial(5)
SCouto
  • 7,808
  • 5
  • 32
  • 49
2

You can see this answer which is a great explanation of your issue. Your problem is you are trying to define apply as tail-recursive but you are not calling itself in the recursive call, you are calling factorial instead.

First off, you should use Function2 as your type for apply likewise:

import scala.annotation.tailrec

import scala.annotation.tailrec
var factorial: Function2[Int, Int, Int] = new Function2[Int, Int, Int] {
    @tailrec override def apply (x:Int, acc:Int=1): Int = {
      if (x<=1) acc
      else apply(x-1, x * acc)
    }
}

And then, if you get the error could not optimize @tailrec annotated method apply: it contains a recursive call targeting a supertype, you should call apply recursively as for a function to be tail recursive it always should be called exactly itself as the last statement.

scala> factorial(5, 1)
res3: Int = 120
nicodp
  • 2,362
  • 1
  • 11
  • 20
0

Function2 take 3 type parameters. Last one is the output type.

Scala REPL

scala> :paste
// Entering paste mode (ctrl-D to finish)

 val fac: Function2[Int, Int, Int] = new Function2[Int, Int, Int] {
    def apply(v1: Int, v2: Int): Int = if (v1 == 1) v2 else apply(v1 - 1, v1 * v2)
  }


// Exiting paste mode, now interpreting.

fac: (Int, Int) => Int = <function2>

scala> fac(5, 1)
res1: Int = 120

You can syntactic sugar (function syntax in scala using =>) instead of using interface/trait Function2.

scala> :paste
// Entering paste mode (ctrl-D to finish)

val fac: (Int, Int) => Int = (acc, c) => if (c == 1) acc else fac(acc * c, c - 1)


// Exiting paste mode, now interpreting.

fac: (Int, Int) => Int = $$Lambda$1092/1204822967@5c83ae01

scala> fac(1, 5)
res0: Int = 120
Nagarjuna Pamu
  • 14,737
  • 3
  • 22
  • 40
  • Looking at answers from both pamu and Yevhenii Popadiuk, the mistake I did was when calling the function, since i was declaring the acc=1, when calling the function i was just using fact(5), which caused the problem. But I don't understand even when acc=1 has been declared, when calling it, why should i still pass the value? – Vasu Dec 27 '17 at 13:45
  • 2
    You cannot use default value syntax in this case as it is trait instance creation. You can do this in case of normal function declaration – Nagarjuna Pamu Dec 27 '17 at 13:53
0

Or, if you like some syntactic sugar, you can write it:

  val f: (Int) => BigInt = (x) => {
    if (x <= 1) 1
    else x * f(x - 1)
  }

  println(f(30))

Or true tail-recursive function:

  val f: (Int) => BigInt = (x) => {

    @tailrec
    def helper(x: Int, acc: BigInt = 1): BigInt = {
      if (x <= 1) acc
      else helper(x - 1, x * acc)
    }

    helper(x)
  }

  println(f(30))
Juozas
  • 916
  • 10
  • 17