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
不会阻止上面的堆栈帧被添加到调用堆栈中呢?
答案 0 :(得分:2)
在您的代码中,graphics.off()
par("mar")
par(mar=c(1,1,1,1))
是foo
类型的静态值。请注意,它不具有CallStack
约束。
使用HasCallStack
的方式和位置无关紧要,它始终会引用此特定foo
。使用CallStack
使用foo
机制定义bar
本身并不重要 - 您可以静态定义HasCallStack
。
尝试将foo = [("bar",…
添加到HasCallStack =>
的类型签名中。它现在的表现如你所愿吗?