在Scala中编写阶乘尾递归函数

时间:2017-12-27 13:24:44

标签: scala function recursion functional-programming tail-recursion

我尝试以下面的方式编写尾递归函数,但编译器抛出错误:

方法适用的参数太多:(v1:Int)特征Function1中的Int         其他因子(x-1,x * acc)

我曾尝试用Function2替换Function1并赋予Function2 [Int,Int,Int] = new Function2 [Int,Int,Int]

但它仍然给我带来了同样的错误。有人可以指出我哪里出错了吗?

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)

5 个答案:

答案 0 :(得分:3)

当您通过两个时,apply内的Function1必须只接受一个参数。

您可以按如下方式重写它:

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)
  }
}

答案 1 :(得分:2)

Function1表示具有单个参数的函数(第二个用于输出)

因此,您需要使用单个参数定义apply方法,然后在其中使用嵌套函数执行递归:

  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)

答案 2 :(得分:0)

Function2采用3种类型参数。最后一个是输出类型。

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

你可以使用=>来使用语法糖(scala中的函数语法),而不是使用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

答案 3 :(得分:0)

您可以看到此answer,这是对您的问题的一个很好的解释。你的问题是你试图将apply定义为尾递归,但你没有在递归调用中调用自己,而是调用factorial

首先,你应该使用Function2作为你的类型同样适用:

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)
    }
}

然后,如果你得到错误could not optimize @tailrec annotated method apply: it contains a recursive call targeting a supertype,你应该递归地调用apply,因为函数是尾递归的,它总是应该被称为最后一个语句。

scala> factorial(5, 1)
res3: Int = 120

答案 4 :(得分:0)

或者,如果您喜欢语法糖,可以编写它:

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

  println(f(30))

或真正的尾递归函数:

  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))