在Clojure中,例如,您可以使用recur特殊形式来明确使用非堆栈消耗递归调用的意图,并由编译器进行验证。由于它在Clojure的docs年代写道:有没有一种方法可以明确编写一个elixir函数以进行尾部调用优化?
“在其他复发比的末尾位置是一个错误”, “易复发的功能及其在尾部位置的使用是由编译器验证”
在elixir中,您可以将函数定义为一系列子句,并在它们之间进行递归调用。有没有一种方法可以确定定义的函数将被尾调用优化?
在Clojure中,例如,您可以使用recur特殊形式来明确使用非堆栈消耗递归调用的意图,并由编译器进行验证。由于它在Clojure的docs年代写道:有没有一种方法可以明确编写一个elixir函数以进行尾部调用优化?
“在其他复发比的末尾位置是一个错误”, “易复发的功能及其在尾部位置的使用是由编译器验证”
在elixir中,您可以将函数定义为一系列子句,并在它们之间进行递归调用。有没有一种方法可以确定定义的函数将被尾调用优化?
编译器没有优化函数。它优化了该函数的调用。它可能是对它内部的同一个函数的调用,它可能是对不同函数的调用,没关系。
...这是不使用Clojure,其中recur
只能返回执行到最新“递归点”的情况下(无论是loop
或fn
),使相互递归不可能没有“帮助从外面”如trampoline。这更像是一个带式比解决方案,但问题太大,适当的解决方案将需要太多。
是的,有一种方法可以确保它在Elixir中得到优化:它需要是一个实际的tail call。就这样。
在计算机科学中,尾部调用是作为过程的最终动作执行的子程序调用。
这可以很容易地通过目视检查代码来确定。
如果Clojure的是这样的工作方式,下面的两个定义是等价的:
(defn x [] (x)) ; <- StackOverflowError if called
(defn x [] (recur)) ; <- hangs if called
但是,如果你想执行这一点,否则会失败,你所要做的,要么:
编辑前的后者似乎更实际,最简单的纯功能。
我还没有找到任何现有解决方案。
您是否可以确认一个尾巴呼叫是否只是一个函数调用而没有别的:即如果最后一条语句是'funt(n)',那么这是一个尾部调用,如果它是'1 + funct(n)',将不会被尾部优化。 – DavidC
@DavidC如果对返回值有任何计算(例如,将返回值加1),则必须创建新的堆栈帧,并且该呼叫不能是TCO。 –
简单的答案是调用Erlang和Elixir的TCO,除非您以防止它们的方式对它们进行编码。基本上,如果您对函数的返回值做任何事情,例如将1加入返回值,那么它不是TCO,因为必须维护堆栈。 –