[英]Does every Haskell function do tail calls?
I wondered that every function in Haskell should be tail recursive. 我想知道Haskell中的每个函数都应该是尾递归的。
The factorial function implemented as a non tail recursive function: 阶乘函数实现为非尾递归函数:
fact 0 = 1
fact n = n * fact (n - 1)
Every operator is a function too, so this is equivalent to 每个运算符也是一个函数,所以这等效于
fact 0 = 1
fact n = (*) n (fact (n - 1))
But this is clearly a tail call to me. 但这显然是我的尾声。 I wonder why this code causes stack overflows if every call just creates a new thunk on the heap.
我想知道如果每个调用都只是在堆上创建一个新的thunk,那么这段代码为什么会导致堆栈溢出。 Shouldn't i get a heap overflow?
我不应该堆溢出吗?
In the code 在代码中
fact 0 = 1
fact n = (*) n (fact (n - 1))
the last (*) ...
is a tail call, as you observed. 如您所见,最后一个
(*) ...
是尾部调用。 The last argument fact (n-1)
however will build a thunk which is immediately demanded by (*)
. 但是,最后一个实参
fact (n-1)
将产生一个thunk,紧接着(*)
要求它。 This leads to a non-tail call to fact
. 这导致对
fact
的无尾的呼吁。 Recursively, this will consume the stack. 递归地,这将消耗堆栈。
TL;DR: the posted code performs a tail call, but (*)
does not. TL; DR:发布的代码执行尾部调用,但
(*)
则不执行。
(Also "the stack" in Haskell is a not so clear notion as in strict languages. Some implementations of Haskell use something more complex than that. You can search for "push/enter vs eval/apply" strategies if you want some gory details.) (此外,Haskell中的“堆栈”概念并不像严格的语言中那么清晰。Haskell的某些实现使用的东西要比这复杂得多。如果需要一些详细信息,可以搜索“推入/输入vs评估/应用”策略。 。)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.