【发布时间】:2017-09-02 01:48:38
【问题描述】:
作为一种纯函数式编程语言,Haskell 大量使用递归。 Haskell 中是否会出现堆栈溢出错误,就像在 Java 中一样?为什么,或者为什么不?
【问题讨论】:
-
像 GHC 这样的 Haskell 编译器执行尾调用消除 en.wikipedia.org/wiki/Tail_call。在实现良好的函数式语言中,尾递归函数不会导致堆栈溢出。
-
@JustinL。 Yes it does.
-
惰性函数式语言不需要尾调用消除来避免堆栈溢出。如果您实现一个简单的图形缩减引擎,其中所有内容都在堆上,那么无论如何,尾调用(不仅仅是递归)消除的等价物会因为懒惰而免费; GHC 将尾递归转换为汇编程序循环以提高效率,我并不感到惊讶,但它不需要堆栈管理。实际上可以通过尝试将代码转换为尾递归形式来引入在 Haskell 中可能出现的那种堆栈溢出(嵌套的 thunk 太多,递归深度不够)!
-
在 Haskell 中,使用尾递归可能是有益的,也可能是有害的,具体取决于上下文。例如。使用尾递归和(严格!)累加参数对列表求和是好的。使用尾递归实现
foldr是可怕的,即使忽略无限列表也是如此。 -
在 Java 和其他一些语言中,我认为运行时在堆栈上设置了一个相对任意的界限,因为在这种语言中,递归太多是不习惯的,所以超过 -say- 10000 调用帧是非常规的,因此被禁止,即使操作系统内存允许更大的堆栈。 (然而,JVM 有一个改变限制的标志)因此,我猜许多程序员“知道”递归本质上是不好的,在命令式代码中应该不惜一切代价避免。这加强了递归的单一性。
标签: haskell recursion stack-overflow