为什么Clojure有"复发"特殊形式?
当我用函数本身替换"recur"时,我得到相同的结果:
(defn print-down-from [x]
(when (pos? x)
(println x)
(recur (dec x))
)
)
(print-down-from 5)
Run Code Online (Sandbox Code Playgroud)
结果与...相同
(defn print-down-from [x]
(when (pos? x)
(println x)
(print-down-from (dec x))
)
)
(print-down-from 5)
Run Code Online (Sandbox Code Playgroud)
我想知道"recur"是否只是一个安全措施,因此如果开发人员碰巧使用非尾递归,编译器将抛出错误.或者编译器可能需要优化尾递归?
但我最想知道的是除了堆栈消费之外的任何其他原因.
Cha*_*ffy 13
正如关于函数式编程的clojure.org页面中所解释的那样:
在没有可变局部变量的情况下,循环和迭代必须采用与内置for或while结构的语言不同的形式,这些结构由更改状态控制.在函数式语言中,循环和迭代通过递归函数调用替换/实现.许多这样的语言保证在尾部位置进行的函数调用不消耗堆栈空间,因此递归循环利用恒定空间.由于Clojure使用Java调用约定,因此它不能也不会产生相同的尾调用优化保证.相反,它提供了recur特殊运算符,它通过重新绑定和跳转到最近的封闭循环或函数帧来执行常量空间递归循环.虽然不像尾部调用优化那样通用,但它允许大多数相同的优雅结构,并且提供了检查对recur的调用只能发生在尾部位置的优点.
当你不使用recur(或trampoline)时,你的函数调用消耗堆栈:因此,如果你运行(print-down-from 100000),你会很快发现崩溃.
那么,提供这种语言设施可以带来以下好处:
recur不消耗堆栈.最后,有关背景知识,请参阅有关StackOverflow主题的其他几个问题之一:
recur不必要的自动工具).