Suppose I start with a function
fromJust Nothing = error "fromJust got Nothing!"
fromJust (Just x) = x
Then, I want to add source information via Template Haskell for better error messages. Let's imagine that I could add an extra parameter to the function
fromJust' loc Nothing = error $ "fromJust got Nothing at " ++ (loc_filename loc)
fromJust' loc (Just x) = x
and then have some fromJust
macro that I could use in source code like,
x = $fromJust $ Map.lookup k m
hack
I did manage to hack it, by using quasiquotes and lifting the string of the source filename. It seems that Loc
doesn't have a Lift instance. Is there a better way?
fromJustErr' l (Nothing) =
error $ printf "[internal] fromJust error\
\\n (in file %s)" l
fromJustErr' l (Just x) = x
fromJustErr = do
l <- location
let fn = loc_filename l
fnl :: Q Exp = TH.lift fn
[| fromJustErr' $fnl |]
Thanks!
(I know it's nicer to fmap
stuff via the Maybe
functor than use fromJust
, but I need to hack sometimes.)
Here's an attempt at making this pattern somewhat more reusable.
The key idea is to pass a customized
error
to our function which will include the location in the error message. You'd use it like this:Using this function is similar to your original approach:
Now, for the Template Haskell that makes this work:
locatedError
produces the customizederror
function, given a location.withLocatedError
feeds this tofromJust'
to hook everything together.formatLoc
just formats the location nicely into a string.Running this gives us the result we wanted:
How about making a new error function?
Then use it like
(It's incomplete -- doesn't give the message, just the file, but you get the idea)
EDIT
On re-reading your question, I realize this isn't what you're trying to do. It's an interesting idea -- you're trying to get caller location information -- sort of like a stack trace but only one layer deep. I have no idea how that would work.
Though I guess you could use the same trick of
locError
to makelocFromJust
-- but you wanted a general way, which this isn't.