为什么HasCallStack在使用withFrozenCallStack时仍然添加堆栈帧?

时间:2016-11-28 23:47:15

标签: haskell callstack

GHC 8从HasCallStack模块提供GHC.Stack,允许函数在调用时记录请求堆栈帧。它还提供withFrozenCallStack函数,它“冻结”调用堆栈,以便不再向其添加任何帧。

在简单的场景中,这可以像我期望的那样工作。例如:

ghci> let foo :: HasCallStack => CallStack
          foo = callStack
ghci> foo
[("foo",SrcLoc {srcLocPackage = "interactive", srcLocModule = "Ghci2", srcLocFile = "<interactive>", srcLocStartLine = 8, srcLocStartCol = 1, srcLocEndLine = 8, srcLocEndCol = 4})]
ghci> withFrozenCallStack foo
[]

当我正常调用foo时,我得到一个堆栈帧,但是当我用withFrozenCallStack包裹它时,我没有。完善。但是,当示例稍微复杂一点时,它会停止表现得像我期望的那样:

ghci> let foo :: CallStack
          foo = bar
          bar :: HasCallStack => CallStack
          bar = callStack
ghci> foo
[("bar",SrcLoc {srcLocPackage = "interactive", srcLocModule = "Ghci9", srcLocFile = "<interactive>", srcLocStartLine = 24, srcLocStartCol = 11, srcLocEndLine = 24, srcLocEndCol = 14})]
ghci> withFrozenCallStack foo
[("bar",SrcLoc {srcLocPackage = "interactive", srcLocModule = "Ghci9", srcLocFile = "<interactive>", srcLocStartLine = 24, srcLocStartCol = 11, srcLocEndLine = 24, srcLocEndCol = 14})]

通过添加这个简单的间接层,尽管使用了withFrozenCallStack,仍然可以包含堆栈帧。为什么呢?

从概念上讲,我对HasCallStack的理解是它就像在当前调用堆栈上隐式使用pushCallStack,而pushCallStack对冻结的调用堆栈没有影响。那么,为什么withFrozenCallStack不会阻止上面的堆栈帧被添加到调用堆栈中呢?

1 个答案:

答案 0 :(得分:2)

在您的代码中,graphics.off() par("mar") par(mar=c(1,1,1,1))foo类型的静态值。请注意,它具有CallStack约束。

使用HasCallStack的方式和位置无关紧要,它始终会引用此特定foo。使用CallStack使用foo机制定义bar本身并不重要 - 您可以静态定义HasCallStack

尝试将foo = [("bar",…添加到HasCallStack =>的类型签名中。它现在的表现如你所愿吗?