标签: tail-recursion

Haskell尾递归如何工作?

我写了这段代码,我假设len是尾递归,但仍然会发生堆栈溢出.怎么了?

myLength :: [a] -> Integer

myLength xs = len xs 0
    where len [] l = l
          len (x:xs) l = len xs (l+1)

main = print $ myLength [1..10000000]
Run Code Online (Sandbox Code Playgroud)

haskell tail-recursion

48
推荐指数
2
解决办法
9282
查看次数

是否存在无法使用尾递归编写的问题?

尾递归是函数式语言中一个重要的性能优化策略,因为它允许递归调用消耗常量堆栈(而不是O(n)).

是否有任何问题根本无法以尾递归方式编写,或者总是可以将天真递归函数转换为尾递归函数?

如果是这样,有一天功能编译器和解释器可能足够智能以自动执行转换?

recursion functional-programming tail-recursion

47
推荐指数
4
解决办法
6799
查看次数

除非方法是最终的,否则为什么Scala编译器不会应用尾调用优化?

除非方法是最终的,否则为什么Scala编译器不会应用尾调用优化?

例如,这个:

class C {
    @tailrec def fact(n: Int, result: Int): Int =
        if(n == 0)
            result
        else
            fact(n - 1, n * result)
}
Run Code Online (Sandbox Code Playgroud)

结果是

错误:无法优化@tailrec带注释的方法:它既不是私有的也不是最终的,因此可以被覆盖

如果编译器在这种情况下应用TCO,究竟会出现什么问题呢?

scala tail-recursion tail-call-optimization

45
推荐指数
3
解决办法
4172
查看次数

尾递归风格的代码不是吗?

我对Scala的新手在尝试阅读David Pollack的Beggining Scala时有点新意.他定义了一个简单的递归函数,它从文件中加载所有字符串:

def allStrings(expr: => String): List[String] = expr match {
    case null => Nil
    case w => w :: allStrings(expr)
}
Run Code Online (Sandbox Code Playgroud)

它优雅而且很棒,只是当我试图加载一个庞大的字典文件时它抛出了一个StackOverflow异常.

现在据我所知,Scala支持尾递归,因此函数调用不可能溢出堆栈,可能编译器无法识别它?所以经过一些谷歌搜索后我尝试了@tailrec注释来帮助编译器,但它说

error: could not optimize @tailrec annotated method: it contains a recursive call not in tail position
def allStrings(expr: => String): List[String] =
Run Code Online (Sandbox Code Playgroud)

我理解尾递归错了吗?我该如何修复此代码?

functional-programming scala tail-recursion

45
推荐指数
2
解决办法
8762
查看次数

生成尾调用操作码

出于好奇,我试图使用C#生成尾调用操作码.Fibinacci是一个简单的,所以我的c#示例如下所示:

    private static void Main(string[] args)
    {
        Console.WriteLine(Fib(int.MaxValue, 0));
    }

    public static int Fib(int i, int acc)
    {
        if (i == 0)
        {
            return acc;
        }

        return Fib(i - 1, acc + i);
    }
Run Code Online (Sandbox Code Playgroud)

如果我在发布中构建并在没有调试的情况下运行它,我就不会出现堆栈溢出.在没有优化的情况下调试或运行它,我确实得到了堆栈溢出,这意味着尾部调用在发布时具有优化功能(这是我的预期).

这个MSIL看起来像这样:

.method public hidebysig static int32 Fib(int32 i, int32 acc) cil managed
{
    // Method Start RVA 0x205e
    // Code Size 17 (0x11)
    .maxstack 8
    L_0000: ldarg.0 
    L_0001: brtrue.s L_0005
    L_0003: ldarg.1 
    L_0004: ret 
    L_0005: ldarg.0 
    L_0006: ldc.i4.1 
    L_0007: sub 
    L_0008: ldarg.1 
    L_0009: ldarg.0 
    L_000a: …
Run Code Online (Sandbox Code Playgroud)

c# recursion f# cil tail-recursion

39
推荐指数
3
解决办法
7245
查看次数

为什么我的Scala尾递归比while循环更快?

这里有两个解决方案,在Cay Horstmann的Scala for the Impatient中运用4.9:"写一个函数lteqgt(values:Array [Int],v:Int),它返回一个包含小于v的值的三元组,等于v,并且大于v." 一个使用尾递归,另一个使用while循环.我认为两者都会编译成类似的字节码,但是while循环比尾递归慢了近两倍.这告诉我,我的while方法编写得很糟糕.

import scala.annotation.tailrec
import scala.util.Random
object PerformanceTest {

  def main(args: Array[String]): Unit = {
    val bigArray:Array[Int] = fillArray(new Array[Int](100000000))
    println(time(lteqgt(bigArray, 25)))
    println(time(lteqgt2(bigArray, 25)))
  }

  def time[T](block : => T):T = {
    val start = System.nanoTime : Double
    val result = block
    val end = System.nanoTime : Double
    println("Time = " + (end - start) / 1000000.0 + " millis")
    result
  }

  @tailrec def fillArray(a:Array[Int], pos:Int=0):Array[Int] = {
    if (pos == a.length)
      a
    else { …
Run Code Online (Sandbox Code Playgroud)

performance loops scala tail-recursion

35
推荐指数
2
解决办法
3759
查看次数

什么是尾递归消除?

Steve Yegge在一篇博客文章中提及它,我不知道这意味着什么,有人可以填写我吗?

它与尾部调用优化是一回事吗?

language-agnostic recursion tail-recursion tail-call-optimization program-transformation

33
推荐指数
2
解决办法
8449
查看次数

F#尾递归函数示例

我是F#的新手,正在阅读有关尾递归函数的内容,希望有人可以给我两个不同的函数foo实现 - 一个是尾递归的,另一个不是我可以更好地理解这个原理.

f# tail-recursion

33
推荐指数
4
解决办法
2万
查看次数

C尾调用优化

我经常听到人们说C不执行尾部呼叫消除.虽然标准不能保证,但是无论如何,它是否在实践中通过任何体面的实现来执行?假设你只针对成熟的,实现良好的编译器而不关心为模糊平台编写的原始编译器的绝对最大可移植性,那么在C中依赖尾调用是否合理呢?

另外,将尾部呼叫优化留在标准之外的理由是什么?

c standards tail-recursion tail-call-optimization

32
推荐指数
3
解决办法
1万
查看次数

Go中的尾部调用优化

到目前为止,Go编程语言是否优化尾调用?如果没有,它是否至少优化了函数的尾递归调用?

tail-recursion go tail-call-optimization

32
推荐指数
3
解决办法
7699
查看次数