stack-overflow - Elixir无限递归是否曾经使堆栈溢出?

标签 stack-overflow elixir

Elixir编程中A numberdifferent 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的结果是barbaz的结果,因此无需将任何内容压入堆栈。

相反,如果调用方函数在调用另一个函数之后执行了某些操作,则它不是尾部调用,并且不会发生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/

相关文章:

scala - netbeans 7.0 和 scala 导致 stackoverflow

postgresql - Phoenix/Ecto - 查询字符串数组中的匹配项

kotlin - 在使用 Android 数据绑定(bind)和 Kotlin 的自定义 BindingAdapter 中使用 lambda

elixir - 人性化的绳子修剪

Elixir:救援/捕获任务超时

elixir - 首次通过编辑创建关联时新建和编辑变更集

elixir - 函数 '<-'/2 未定义接收 block Elixir 中的错误

c - -fno-stack-protector 有什么用?

java - 线程中的异常 "main"java.lang.StringIndexOutOfBoundsException : String index out of range: -3

c# - 递归中的堆栈溢出