I have Exception type UnknownException
, which I'd like to include the CallStack when it's thrown.
module Main where
import Control.Exception (Exception, throw)
newtype UnknownException = UnknownException
{ caller :: String
} deriving (Show)
instance Exception UnknownException
main :: IO ()
main = willThrow
willThrow :: IO ()
willThrow = throw $ UnknownException "willThrow"
I'd like the above example to print logs like this
example-exe: UnknownException {caller = "willThrow"}
CallStack (from HasCallStack):
willThrow, called at app/Main.hs:16:13 in main:Main
main, called at app/Main.hs:13:8 in main:Main
but actually printed:
example-exe: UnknownException {caller = "willThrow"}
Also, is it a good practice to include CallStack in exceptions in Haskell?
Yeah I think it is good practice. If you are compiling with profiling, you can simply use
currentCallStack :: IO [String]
from GHC.Stack
. Notice that it's in IO
but I would consider it fine to unsafePerformIO
this when you throw the error if you are in pure code. Because all bottoms are equal denotationally, there's not really any violation of purity.
But if you want to get at call stacks without profiling (say you want to include it in a log message on production), you have to do more. You have to include HasCallStack
constraints everywhere you would like the stack to be reported. So
main :: IO ()
main = print f
f :: Int
f = g
g :: HasCallStack => Int
g = h
h :: HasCallStack => Int
h = error (show callStack)
Will report the call stack up to g
, but will omit f
. Sadly,
If there is no CallStack in scope and the enclosing definition has an explicit type signature, GHC will solve the HasCallStack constraint for the singleton CallStack containing just the current call-site.
That means it will omits any callers of f
, even if they do have HasCallStack
just because f
doesn't have such a constraint. I find this terribly cumbersome.
It's a fairly recent feature, so I hope the GHC team has something better in mind that they using this to move toward.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With