Function Can函数尾部递归

Function Can函数尾部递归,function,scala,tail-recursion,Function,Scala,Tail Recursion,我有一些递归代码,我想重构以使用尾部递归,我可以将递归简化为这样,请忽略此功能想要实现的功能 @tailrec def doStuff: List[Int] => Int = { case Nil => 0 case x :: xs => doStuff(xs) } 如果我去掉tailrec注释,它工作得很好,结构看起来像这个doStuff(doStuff(doStuff(…))。它将有stackoverflow异常 那么,如果它是一个函数,我

我有一些递归代码,我想重构以使用尾部递归,我可以将递归简化为这样,请忽略此功能想要实现的功能

@tailrec
def doStuff: List[Int] => Int = {
      case Nil => 0
      case x :: xs => doStuff(xs)
    }
如果我去掉tailrec注释,它工作得很好,结构看起来像这个doStuff(doStuff(doStuff(…))。它将有stackoverflow异常


那么,如果它是一个函数,我怎样才能使它成为尾部递归的呢

@tailrec
def doStuff(list: List[Int]): Int = list match {
  case Nil => 0
  case x :: xs => doStuff(xs)
}

也许你是说这个

@tailrec
def doStuff(list: List[Int]): Int = list match {
  case Nil => 0
  case x :: xs => doStuff(xs)
}

匿名函数不能成为尾部递归函数。让我们首先对代码进行一次非常简单的重写,引入一个
val
来保存结果函数

@tailrec
def doStuff: List[Int] => Int = {
  val result: List[Int] => Int = {
    case Nil => 0
    case x :: xs => doStuff(xs)
  }
  result
}
从这里可以清楚地看到,
doStuff(xs)
并没有调用匿名函数本身。它正在调用方法
doStuff
,该方法返回要调用的函数。更糟糕的是,由于它是一个
def
,它实际上在每次调用时都返回不同的函数。因此,匿名函数肯定不是在调用自己

问题归结为一个简单的事实:匿名函数是匿名的。因此,他们无法直接调用自己:他们总是调用其他可能返回自己的
def
val
,但编译器不知道这一点

因此,只有像@dhg建议的那样适当的
def
s才是真正的尾部递归

现在,如果您真的想返回一个函数值,它恰好是通过尾部递归案例实现的,那么您可以使用
方法将一个方法转换为一个函数。因此,初始问题的解决方案如下:

val doStuff = {
  @tailrec
  def rec(list: List[Int]): Int = list match {
    case Nil => 0
    case x :: xs => rec(xs)
  }
  rec _
}

请注意,我们声明了一个正确的尾部递归方法(
rec
),然后将其转换为带有
rec

的函数值,匿名函数不能成为尾部递归函数。让我们首先对代码进行一次非常简单的重写,引入一个
val
来保存结果函数

@tailrec
def doStuff: List[Int] => Int = {
  val result: List[Int] => Int = {
    case Nil => 0
    case x :: xs => doStuff(xs)
  }
  result
}
从这里可以清楚地看到,
doStuff(xs)
并没有调用匿名函数本身。它正在调用方法
doStuff
,该方法返回要调用的函数。更糟糕的是,由于它是一个
def
,它实际上在每次调用时都返回不同的函数。因此,匿名函数肯定不是在调用自己

问题归结为一个简单的事实:匿名函数是匿名的。因此,他们无法直接调用自己:他们总是调用其他可能返回自己的
def
val
,但编译器不知道这一点

因此,只有像@dhg建议的那样适当的
def
s才是真正的尾部递归

现在,如果您真的想返回一个函数值,它恰好是通过尾部递归案例实现的,那么您可以使用
方法将一个方法转换为一个函数。因此,初始问题的解决方案如下:

val doStuff = {
  @tailrec
  def rec(list: List[Int]): Int = list match {
    case Nil => 0
    case x :: xs => rec(xs)
  }
  rec _
}
请注意,我们声明了一个适当的尾部递归方法(
rec
),然后使用
rec
将其转换为函数值

那么,如果它是一个函数,我如何使它成为尾部递归的呢

你不能。我的意思是,当然你可以在Scala中编写一个尾部递归函数,但它不会帮助你,因为它不会得到优化

Scala只优化直尾递归方法调用

那么,如果它是一个函数,我如何使它成为尾部递归的呢

你不能。我的意思是,当然你可以在Scala中编写一个尾部递归函数,但它不会帮助你,因为它不会得到优化


Scala只优化直尾递归方法调用。

不太好,它的返回类型是Int,我仍然希望返回类型是一个函数。如果您在本文中查看enumerateFile的实现。几乎所有的递归函数都不是尾部递归的。这是我想要改变的。@Cloudtech不是真的,它的返回类型是Int,我仍然希望返回类型是一个函数。如果您在本文中查看enumerateFile的实现。几乎所有的递归函数都不是尾部递归的。这是我想要改变的。@Cloudtech