我的理解是尾递归是递归,其中返回值不是完成操作所必需的;也就是说,递归是函数的最后一步,一旦它进行递归调用,函数的其余部分就完成了。
对此,我问这个例子(来自Norvig先生)是否是尾递归:
(defparameter *titles*
'(Mr Mrs Miss Ms Sir Madam Dr Admiral Major General)
"A list of titles that can appear at the start of a name.")
(defun first-name (name)
"Select the first name from a name represented as a list."
(if (member (first name) *titles*)
(first-name (rest name))
(first name)))
一旦最后的first-name
被称为if
语句的一个分支,那么该函数没有其他功能;因此,它是尾递归?
答案 0 :(得分:2)
是的,这是一个例子。
尾部递归优化在Common Lisp的许多实现中都可用,但规范并不要求它。 这意味着您可以使用Common Lisp而无需尾递归优化。
您可能还会发现您正在使用的版本需要稍微调整才能执行此优化。
因此在某些实现中,您可能需要使用'declare'来通知编译器您希望优化速度。
(defun first-name (name)
"Select the first name from a name represented as a list."
(declare (optimize (speed 3) (compilation-speed 0) (debug 0) (safety 1)))
(if (member (first name) *titles*)
(first-name (rest name))
(first name)))
修改强> This site现在已有几年了,但可能会提供一些信息。
当Joshua和Rainer在这里大量改进细节时,请务必阅读评论。
答案 1 :(得分:2)
是和否。通常是的。如果编译器支持TCO并且正确的优化设置处于活动状态,它也将进行优化。 但有时编译器无法对其进行优化。
如果name
被宣布为特殊,那么可能不会。
如果有类似
的话(defvar name '(susanne mustermann))
然后函数的参数name
将被声明为 special (它将使用动态绑定)。然后编译器可能不会在first-name
函数中使用尾调用优化。
这意味着您还需要知道变量符号是否被声明为特殊符号。
这是其中一个原因,全局特殊变量应该像*name*
一样编写,以防止特殊声明那些应该是词汇变量的局部变量。在这种情况下,特殊声明也会阻止TCO。
我们最好写一下:
(defvar *name* '(susanne mustermann))