Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/8.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Haskell 折叠左尾递归吗?_Haskell_Recursion - Fatal编程技术网

Haskell 折叠左尾递归吗?

Haskell 折叠左尾递归吗?,haskell,recursion,Haskell,Recursion,我想问,函数foldl是否是尾部递归 当我查看源代码时,foldl是如何实现的: foldl :: (b -> a -> b) -> b -> [a] -> b foldl f acc [] = acc foldl f acc (x:xs) = foldl f (f acc x) xs 它看起来像一个尾部递归 左折叠始终是左关联的。假设我有以下表达式: foldl (*) 1 [1..3] 然后,它将评估为: ((1 * 1) * 2) * 3 然后写下步骤,

我想问,函数
foldl
是否是尾部递归

当我查看源代码时,
foldl
是如何实现的:

foldl :: (b -> a -> b) -> b -> [a] -> b
foldl f acc [] = acc
foldl f acc (x:xs) = foldl f (f acc x) xs
它看起来像一个尾部递归

左折叠始终是左关联的。假设我有以下表达式:

foldl (*) 1 [1..3]
然后,它将评估为:

((1 * 1) * 2) * 3
然后写下步骤,我想:

foldl (*) 1 [1..3] =
foldl (*) (1 * 1) [2,3]
foldl (*) (1 * 2) [3]
foldl (*) (2 * 3) []
6

不像
((1*1)*2)*3
,还是我错了?

foldl
f
严格时表示尾部递归。你说得对,最好是

foldl (*) 1 [1,2,3] = 
foldl (*) 1 [2,3]   = 
foldl (*) 2 [3]     = 
foldl (*) 6 []      = 
6 
如果
f
不严格,即保留其参数表达式的原样,待以后计算,则最终会得到类似
(((1*1)*2)*3)
的嵌套表达式,这甚至会在最终求值时导致堆栈溢出,这是不必要的,因为要求值此类嵌套表达式,必须使用堆栈:

(((1*1)*2)*3) 
=> x * 3 where x = ((1*1)*2)
            => x = y*2 where y = 1*1
                             y <= 1
            => x = 1*2
            <= x = 2
=> 2 * 3
<= 6
(((1*1)*2)*3)
=>x*3,其中x=((1*1)*2)
=>x=y*2,其中y=1*1
y x=1*2
2 * 3

Haskell没有尾部递归的概念。它使用惰性评估或thunks。啊哈,好吧,这是什么意思?什么是thunks?此链接提供有关Haskell如何优化递归的信息@里奇汉:我有点不同意。Haskell中确实存在尾部递归(或一般的尾部调用),但它不像在严格的函数式语言中那样是个好主意。事实上,如果不注意严格,在开始真正的工作之前,很容易让它的尾部递归函数积累大量的thunk。正因为如此,我认为
foldl
始终是个坏主意,
foldl'
是“真正的”左折叠,它为调用方提供控制,以便严格程度可以得到控制。尾部递归只是指函数立即返回递归调用返回的值,而不做任何进一步的工作。尾部调用优化(tailcalloptimization,TCO)是一种语言实现特性,它为递归调用重用堆栈框架,因为调用方不再需要它。