为何haskell没有异常堆栈

在Haskell中,默认情况下,抛出异常并不会像其他语言(例如Java或Python)那样自动打印堆栈跟踪。

惰性求值意味着表达式不会立即计算,而是等到需要它时才会计算,这对于异常的传播有影响。

1
2
3
4
5
6
7
8
9
10
11
12
13
import Debug.Trace (trace)

someFunc :: IO ()
someFunc = do
let a = f1
b = f2 a
print b

f1 :: Int
f1 = trace "run f1" 10

f2 :: Int -> Int
f2 val = trace "run f2" val + 10

执行结果为

1
2
3
run f2
run f1
20

正常的栈应该是

1
2
3
4
5
someFunc 入 : [someFunc]
f1 入 : [someFunc, f1]
f1 出 : [someFunc]
f2 入 : [someFunc, f2]
f2 出 : [someFunc]

但是在haskell可能是下面这样,跟代码的表现完全不一样,这时候会疑惑f2方法哪里调用了f1,这在实际的代码中会更复杂。

1
2
3
4
5
someFunc 入 : [someFunc]
f2 入 : [someFunc, f2]
f1 入 : [someFunc, f2, f1]
f1 出 : [someFunc, f2]
f2 出 : [someFunc]

另外一个原因是因为ghc优化也会导致堆栈难以跟踪,如上例子,f1可能直接优化到f2中形成组合函数。