Why does HasCallStack still add stack frames when using withFrozenCallStack?

GHC 8 provides HasCallStack from the GHC.Stack module, which allows you to write functions to request the stack frame when they are called. It also provides a withFrozenCallStack function that freezes the call stack so that no additional frames can be added to it.

In simple scenarios, this works as I expected. For example:

 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 [] 

When I usually call foo , I get the stack stack, but when I wrap it withFrozenCallStack , I do not. Fine. However, when the example gets a little more complicated, it stops behaving the way I expect:

 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})] 

By adding this simple layer of indirection, the stack frame is still included, even though I used withFrozenCallStack . Why?

It’s clear that my understanding of HasCallStack is that it seems to implicitly use pushCallStack in the current call stack, and pushCallStack does not affect the frozen call stack. Why then withFrozenCallStack does not prevent adding the specified stack stack to the call stack?

+7
callstack haskell
source share
1 answer

In your foo code, a static value of type CallStack . Please note that it has no HasCallStack restriction.

No matter how and where you use foo , it will always refer to this CallStack . It doesn't matter that foo itself is defined using bar , which uses HasCallStack mechanisms - you can just statically define foo = [("bar",…

Try adding the HasCallStack => signature to foo s. Now he is behaving as you expect?

+2
source share

All Articles