在lisp中递归是否有限制?

Isa*_*iah 12 lisp recursion common-lisp

我喜欢随时使用递归,这似乎是一种更自然的循环方式然后实际循环.我想知道在lisp中递归是否有任何限制?就像在python中那样,在1000次循环后它会变得怪异吗?你可以用它来说游戏循环吗?

现在测试一下,简单计算递归函数.现在> 7000000!

非常感谢

Sid*_*oor 11

Scheme要求尾部调用优化,并且一些CL实现也提供它.但是,CL并没有强制要求它.

请注意,要使尾调用优化起作用,您需要确保不必返回.例如,Fibonacci的一个简单实现,其中需要返回并添加到另一个递归调用,将不会进行尾调用优化,因此您将耗尽堆栈空间.

  • +1特别提到并非所有递归都是尾调用. (2认同)

mat*_*thk 9

首先,您应该了解尾调用的内容.

尾调用是不消耗堆栈的调用.现在您需要识别何时消耗堆栈.

我们来看一个阶乘的例子:

(defun factorial (n)
    (if (= n 1)
        1
        (* n (factorial (- n 1)))))
Run Code Online (Sandbox Code Playgroud)

这是阶乘的非尾递归实现.为什么?这是因为除了从阶乘返回之外,还有一个待定计算.

(* n ..)
Run Code Online (Sandbox Code Playgroud)

因此,每次调用阶乘时,您都会堆叠n.现在让我们编写尾递归因子:

(defun factorial-opt (n &key (result 1))
    (if (= n 1)
        result
        (factorial-opt (- n 1) :result (* result n))))
Run Code Online (Sandbox Code Playgroud)

这里,结果作为参数传递给函数.所以你也在使用堆栈,但区别在于堆栈大小保持不变.因此,编译器可以通过仅使用寄存器并将堆栈留空来优化它.

factorial-opt是然后更快,但不太可读. factorial仅限于堆栈的大小factorial-opt不会.所以你应该学习识别尾递归函数,以便知道递归是否有限.

可能有一些编译器技术将非尾递归函数转换为尾递归函数.也许有人可以在这里指出一些链接.

  • 在Common Lisp中,尾调用(即尾部调用)不会消耗任何堆栈空间.这取决于优化设置和编译器. (3认同)