假设我从一个函数开始
fromJust Nothing = error "fromJust got Nothing!"
fromJust (Just x) = x
然后,我想通过Template Haskell添加源信息以获得更好的错误消息。让我们想象一下,我可以在函数中添加一个额外的参数
fromJust' loc Nothing = error $ "fromJust got Nothing at " ++ (loc_filename loc)
fromJust' loc (Just x) = x
然后有一些我可以在源代码中使用的fromJust
宏,如
x = $fromJust $ Map.lookup k m
我确实设法通过使用quasiquotes并解除源文件名的字符串来破解它。似乎Loc
没有Lift实例。还有更好的方法吗?
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 |]
谢谢!
(我知道通过fmap
仿函数比Maybe
仿真更好,而不是使用fromJust
,但我有时需要破解。)
答案 0 :(得分:4)
这是尝试使这种模式更具可重用性。
关键的想法是将自定义error
传递给我们的函数,该函数将包含错误消息中的位置。你会这样使用它:
fromJust' :: (String -> a) -> Maybe a -> a
fromJust' error Nothing = error "fromJust got Nothing!"
fromJust' error (Just x) = x
fromJust :: Q Exp
fromJust = withLocatedError [| fromJust' |]
使用此功能与原始方法类似:
main = print (1 + $fromJust Nothing)
现在,对于使这项工作的模板Haskell:
withLocatedError :: Q Exp -> Q Exp
withLocatedError f = do
let error = locatedError =<< location
appE f error
locatedError :: Loc -> Q Exp
locatedError loc = do
let postfix = " at " ++ formatLoc loc
[| \msg -> error (msg ++ $(litE $ stringL postfix)) |]
formatLoc :: Loc -> String
formatLoc loc = let file = loc_filename loc
(line, col) = loc_start loc
in concat [file, ":", show line, ":", show col]
在给定位置的情况下, locatedError
会生成自定义的error
函数。 withLocatedError
将此fromJust'
提供给formatLoc
以将所有内容挂钩。 FromJustTest: fromJust got Nothing! at FromJustTest.hs:5:19
只是将位置很好地格式化为字符串。
运行此功能可以获得我们想要的结果:
{{1}}
答案 1 :(得分:1)
如何制作新的错误功能?
locError :: Q Exp
locError = do
loc <- location
msgName <- newName "msg"
eError <- [|error|]
eCat <- [|(++)|]
let
locStr = loc_filename loc
locLit = LitE (StringL locStr)
pat = VarP msgName
body = AppE eError locLit
return $ LamE [pat] body
然后像
一样使用它foo :: Int
foo = $(locError) "This is an error"
(它不完整 - 不提供信息,只提供文件,但你明白了)
修改
在重新阅读你的问题时,我意识到这不是你想要做的。这是一个有趣的想法 - 您正在尝试获取调用者位置信息 - 有点像堆栈跟踪但只有一层深。我不知道这是怎么回事。
虽然我猜你可以使用locError
制作locFromJust
的相同技巧 - 但是你想要一种通用的方法,但事实并非如此。