我最近了解到了尾递归作为一种方法,当你给它一个太大的数字来进行递归时,它不会崩溃。我意识到我可以轻松地将尾递归重写为while循环,并且它基本上完全相同,这让我感到疑惑 - 当你可以用正常循环做任何事情时,是否有任何递归用途?
是的,递归代码看起来更小并且更容易理解,但它也有可能完全崩溃,而一个简单的循环不会崩溃执行相同的任务。
答案 0 :(得分:0)
我将以Haskell language为例,纯功能:
Haskell中的每个函数都是数学意义上的函数 (即"纯")。即使是副作用的IO操作也只是一个 纯代码生成的描述。没有 语句或指令,只有不能改变的表达式 变量(本地或全局)或访问状态,如时间或随机 号。
因此,在haskell中,递归函数是尾递归的,如果最终的结果 递归调用是函数本身的最终结果。如果 必须进一步处理递归调用的结果(例如,通过添加 它是1,或者将另一个元素放在它的开头),它是 不是尾递归。 (see here)
另一方面,在许多编程语言中,调用函数使用堆栈空间,因此尾递归函数可以构建一大堆对自身的调用,这会浪费内存。由于在尾调用中,包含函数即将返回,实际上可以丢弃其环境,并且可以在不创建新堆栈帧的情况下输入递归调用。这个技巧称为尾调用消除或尾调用优化,允许尾递归函数无限重复。
答案 1 :(得分:0)
距离我发布这个问题已经有很长时间了,我对该主题的看法已经改变。原因如下:
我学到了Haskell,这是一门解决递归问题的语言-递归定义和算法被转换为普通的循环算法,并且在大多数情况下,您甚至不直接使用递归,而是使用map
, fold
,filter
或它们的组合。在清除了所有不良问题之后,函数式编程的优点开始显现出来-一切都接近其数学定义,而不会被笨拙的循环和变量所遮盖。
对于要努力理解递归为什么很棒的其他人,请学习Haskell。它具有许多其他非常有趣的功能,例如:懒惰(仅在请求值时才评估值),静态(永远不能修改变量),纯净(函数除了输入和返回输出外不能执行其他任何操作,因此不进行打印)到控制台),使用非常有表现力的类型系统进行强类型键入,其中充斥着令人赞叹的抽象概念,例如Functor,Monad,State等。我几乎可以说这改变了生活。