Elixir编程中A number的different how-tos表示,通过将数据旋转成一个Agent或Task或无限递归需要状态的函数,来惯用地完成存储状态或运行无限循环的观点。他们没有提及递归可以进行的深度限制或任何其他警告。
由于搜索“ Elixir堆栈溢出”只会导致对该网站的访问,因此,我消除歧义并在此处询问:Elixir中有哪些实现保证可确保不会导致无限递归作为“循环”方法堆栈溢出,尤其是在沿途传送状态信息时?
最佳答案
总结一下Hristo的精彩评论,通用机制称为“尾部调用优化”(TCO),它可以确保如果一个函数所做的最后一件事情是调用另一个函数(或其本身),则不会进行堆栈推送。相反,将发生简单的跳转。
关于什么是尾叫,有些细微的差别。让我们看几个例子。最简单的一个是:
def foo do
# ...
bar(...) # tail call -> nothing is pushed to the stack
end
TCO还将适用于条件表达式:
def foo do
# ...
if (...) do
# ...
bar(...) # tail call
else
# ...
baz(...) # tail call
end
end
之所以可行,是因为函数最后要做的就是调用函数。
if
的结果是bar
或baz
的结果,因此无需将任何内容压入堆栈。相反,如果调用方函数在调用另一个函数之后执行了某些操作,则它不是尾部调用,并且不会发生TCO:
def foo do
# ...
# Not a tail call since we're doing something after bar returns
# (increment the result by 1)
1 + bar(...)
end
破坏TCO的另一个示例是在
try
中调用该函数:def foo do
try do
bar(...) # not a tail call
rescue
# ...
end
end
还值得一提的是,由于TCO,发生异常时,您不会在堆栈跟踪中看到某些功能:
def foo do
# ...
bar(...) # at this point foo "disappears" from stack trace
end
def bar(...) do
# ...
raise("error")
end
此错误的堆栈转储将不包含
foo
,因为它不再位于堆栈中(已有效地替换为bar
)。
关于stack-overflow - Elixir无限递归是否曾经使堆栈溢出?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32164370/