为什么HasCallStack在使用withFrozenCallStack时还是会添加栈帧?
Why does HasCallStack still add stack frames when using withFrozenCallStack?
GHC 8 从 GHC.Stack
模块中提供了 HasCallStack
,它允许函数在调用时请求记录堆栈帧。它还提供了 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
不阻止将上述堆栈帧添加到调用堆栈中呢?
在您的代码中,foo
是类型 CallStack
的静态值。请注意,它 没有 具有 HasCallStack
约束。
无论您如何以及在何处使用 foo
,它始终指的是这个特定的 CallStack
。 foo
本身使用 bar
定义并不重要,它使用 HasCallStack
机制——您可以静态定义 foo = [("bar",…
.
尝试将 HasCallStack =>
添加到 foo
的类型签名中。它现在的行为是否符合您的预期?
GHC 8 从 GHC.Stack
模块中提供了 HasCallStack
,它允许函数在调用时请求记录堆栈帧。它还提供了 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
不阻止将上述堆栈帧添加到调用堆栈中呢?
在您的代码中,foo
是类型 CallStack
的静态值。请注意,它 没有 具有 HasCallStack
约束。
无论您如何以及在何处使用 foo
,它始终指的是这个特定的 CallStack
。 foo
本身使用 bar
定义并不重要,它使用 HasCallStack
机制——您可以静态定义 foo = [("bar",…
.
尝试将 HasCallStack =>
添加到 foo
的类型签名中。它现在的行为是否符合您的预期?