GHC.Stack.HasCallStack
is a lightweight method of obtaining a partial call-stack at any point in the program.
A function can request its call-site with the HasCallStack
constraint and access it as a Haskell value by using callStack
.
One can then use functions from GHC.Stack
to inspect or pretty print (as is done in f
below) the call stack.
f :: HasCallStack => IO ()
f = putStrLn (prettyCallStack callStack)
g :: HasCallStack => IO ()
g = f
Evaluating f
directly shows a call stack with a single entry, while evaluating g
, which also requests its call-site, shows two entries, one for each computation “annotated” with HasCallStack
.
ghci> f
CallStack (from HasCallStack):
f, called at <interactive>:19:1 in interactive:Ghci1
ghci> g
CallStack (from HasCallStack):
f, called at <interactive>:17:5 in main:Main
g, called at <interactive>:20:1 in interactive:Ghci2
The error
function from the Prelude supports printing the call stack that led to the error in addition to the usual error message:
ghci> error "bad"
*** Exception: bad
CallStack (from HasCallStack):
error, called at <interactive>:25:1 in interactive:Ghci5
The call stack here consists of a single entry, pinpointing the source of the call to error
. However, by annotating several computations with HasCallStack
, figuring out the exact circumstances and sequences of calls that lead to a call to error
becomes a lot easier, as demonstrated with the simple example below.
f :: HasCallStack => IO ()
f = error "bad bad bad"
g :: HasCallStack => IO ()
g = f
h :: HasCallStack => IO ()
h = g
ghci> h
*** Exception: bad bad bad
CallStack (from HasCallStack):
error, called at call-stack.hs:4:5 in main:Main
f, called at call-stack.hs:7:5 in main:Main
g, called at call-stack.hs:10:5 in main:Main
h, called at <interactive>:28:1 in interactive:Ghci1
The CallStack
will only extend as far as the types allow it, for example
myHead :: HasCallStack => [a] -> a
myHead [] = error "empty"
myHead (x:xs) = x
bad :: Int
bad = myHead []
ghci> bad
*** Exception: empty
CallStack (from HasCallStack):
error, called at Bad.hs:8:15 in main:Bad
myHead, called at Bad.hs:12:7 in main:Bad
includes the call-site of error
in myHead
, and of myHead
in bad
, but not the call-site of bad
at the GHCi prompt.
GHC solves HasCallStack
constraints in two steps:
- If there is a
CallStack
in scope – i.e. the enclosing definition has aHasCallStack
constraint – GHC will push the new call-site onto the existingCallStack
. - Otherwise GHC will solve the
HasCallStack
constraint for the singletonCallStack
containing just the current call-site.
Importantly, GHC will never infer a HasCallStack
constraint, you must request it explicitly.
CallStack
is kept abstract, but GHC provides a function
getCallStack :: CallStack -> [(String, SrcLoc)]
to access the individual call-sites in the stack. The String
is the name of the function that was called, and the SrcLoc
provides the package, module, and file name, as well as the line and column numbers.
GHC.Stack
additionally exports a function withFrozenCallStack
that allows users to freeze the current CallStack
, preventing any future push operations from having an effect. This can be used by library authors to prevent CallStack
s from exposing unnecessary implementation details. Consider the myHead
example above, the error
line in the printed stack is not particularly enlightening, so we might choose to suppress it by freezing the CallStack
that we pass to error
.
myHead :: HasCallStack => [a] -> a
myHead [] = withFrozenCallStack (error "empty")
myHead (x:xs) = x
ghci> myHead []
*** Exception: empty
CallStack (from HasCallStack):
myHead, called at Bad.hs:12:7 in main:Bad
NOTE: The intrepid user may notice that HasCallStack
is just an alias for an implicit parameter ?callStack :: CallStack
. This is an implementation detail and should not be considered part of the CallStack
API, we may decide to change the implementation in the future.
6.19.5.1. Compared with other sources of stack traces
HasCallStack
does not interact with the RTS and does not require compilation with -prof
. On the other hand, as the CallStack
is built up explicitly via the HasCallStack
constraints, it will generally not contain as much information as the simulated call-stacks maintained by the RTS.