例如,在Clojure中,您可以使用recur特殊形式来明确使用非堆栈消耗递归调用的意图,并由编译器进行验证。正如它在Clojure docs中所写的那样:
“在尾部位置以外重复是错误的”, “recur功能正常,它在尾部位置的使用由编译器验证”
在elixir中,您可以将函数定义为一系列子句,并在它们之间进行递归调用。有没有办法确定定义的函数将被尾部调用优化?
答案 0 :(得分:4)
编译器没有优化功能。它优化了该功能的调用。它可能是对其中相同功能的调用,它可能是对不同功能的调用,它并不重要。
...这不是Clojure的情况,其中recur
只能将执行返回到最新"递归点" (无论是loop
还是fn
)如果没有来自外部"的帮助,例如trampoline,就无法进行相互递归。它更像是一个 bandaid 而不是一个解决方案,但问题太大了,一个合适的解决方案需要太多。
是的,有一种方法可以确保它在Elixir中得到优化:它必须是实际的tail call 。这就是全部。
在计算机科学中,尾调用是作为过程的最终动作执行的子程序调用。
这可以通过目视检查代码轻松确定。
如果Clojure以这种方式工作,以下两个定义将是等效的:
(defn x [] (x)) ; <- StackOverflowError if called
(defn x [] (recur)) ; <- hangs if called
但如果你想强制执行,否则就失败了,你必须这样做:
后者似乎更实用,最简单的纯函数。
我还没有找到任何现有的解决方案。