繁体   English   中英

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

[英]Writing a factorial tail recursive function in Scala

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

方法的参数太多了:(v1: Int)Int in trait Function1 else factorial(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)

当您传递两个参数时,您在Function1 apply必须只采用一个参数。

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

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

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)

您可以看到这个答案,它很好地解释了您的问题。 你的问题是你试图将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

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

或者,如果你喜欢一些语法糖,你可以这样写:

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM