2015-11-28 103 views
4

在Clojure中,例如,您可以使用recur特殊形式来明确使用非堆栈消耗递归调用的意图,并由编译器进行验证。由于它在Clojure的docs年代写道:有没有一种方法可以明确编写一个elixir函数以进行尾部调用优化?

“在其他复发比的末尾位置是一个错误”, “易复发的功能及其在尾部位置的使用是由编译器验证”

在elixir中,您可以将函数定义为一系列子句,并在它们之间进行递归调用。有没有一种方法可以确定定义的函数将被尾调用优化?

+1

简单的答案是调用Erlang和Elixir的TCO,除非您以防止它们的方式对它们进行编码。基本上,如果您对函数的返回值做任何事情,例如将1加入返回值,那么它不是TCO,因为必须维护堆栈。 –

回答

4

编译器没有优化函数。它优化了该函数的调用。它可能是对它内部的同一个函数的调用,它可能是对不同函数的调用,没关系。

...这是不使用Clojure,其中recur只能返回执行到最新“递归点”的情况下(无论是loopfn),使相互递归不可能没有“帮助从外面”如trampoline。这更像是一个带式比解决方案,但问题太大,适当的解决方案将需要太多。

是的,有一种方法可以确保它在Elixir中得到优化:它需要是一个实际的tail call。就这样。

在计算机科学中,尾部调用是作为过程的最终动作执行的子程序调用。

这可以很容易地通过目视检查代码来确定。

如果Clojure的是这样的工作方式,下面的两个定义是等价的:

(defn x [] (x))  ; <- StackOverflowError if called 
(defn x [] (recur)) ; <- hangs if called 

但是,如果你想执行这一点,否则会失败,你所要做的,要么:

编辑前的
  • , G。静态代码分析在部署之前使用一些标记用于“期望的TCO”
  • , G。与测试,将触发堆栈溢出

后者似乎更实际,最简单的纯功能。

我还没有找到任何现有解决方案。

+0

您是否可以确认一个尾巴呼叫是否只是一个函数调用而没有别的:即如果最后一条语句是'funt(n)',那么这是一个尾部调用,如果它是'1 + funct(n)',将不会被尾部优化。 – DavidC

+1

@DavidC如果对返回值有任何计算(例如,将返回值加1),则必须创建新的堆栈帧,并且该呼叫不能是TCO。 –

相关问题