【发布时间】:2017-01-22 13:40:08
【问题描述】:
我一直在尝试理解 Haskell 中的惰性求值,我基本上将其理解为仅在需要时才进行求值。但是当试图有效地实现斐波那契时,我遇到了这个(奇怪的?)行为: 这个实现:
--wrapper function used by both implementations
fib :: Int -> Int
fib x = if x < 0 then 0 else fib2 0 1 x
fib2 :: Int -> Int -> Int -> Int
fib2 x y 0 = x
fib2 x y z = fib2 y (x + y) (z - 1)
即使使用
调用也能正常工作fib 20000000
> -70318061090422843
在递归调用中交换传递的参数时:
fib2 :: Int -> Int -> Int -> Int
fib2 x y 0 = x
fib2 x y z = fib2 (x + y) x (z - 1)
结果:
fib 20000000
>*** Exception: stack overflow
为什么我不必告诉编译器在第一个示例中急切地求值? 为什么第二个例子不起作用,而第一个例子起作用?
为此,我在 Windows 10 上使用了 GHCi 8.0.1。
【问题讨论】:
-
不确定这种情况(可能第一个版本基本上展开为一个循环,而第二个版本继续分配堆栈帧)请参阅stackoverflow.com/questions/13042353/… 以了解类似情况...
-
我感觉它一定与柯里化有关,因为溢出示例在第一个参数中建立了 thunk。
-
请包含 ghci 版本信息。对我来说,这不会发生,而是分配失败(7.6.3)。
-
好吧,就我而言,两者都已经是 TCO,不是吗?在这些答案中,它甚至特别指出要使累积论点严格,对于第一个示例我没有这样做,它仍然有效。这实际上是我困惑的根源。
标签: haskell recursion lazy-evaluation