有什么正确的方法让模板haskell包装一个带有源信息的函数(例如行号) [英] what's the correct way to have template haskell wrap a function with source information (e.g. line number)
问题描述
假设我从一个函数开始
fromJust Nothing = errorfrom just nothing nothing!
fromJust(Just x)= x
然后,我想通过Template添加源信息Haskell更好的错误消息。让我们想象一下,我可以为函数添加一个额外的参数。
fromJust'loc Nothing = error $from Just'Nothing at+ +(loc_filename loc)
fromJust'loc(Just x)= x
一些 fromJust
我可以在源代码中使用的宏,如$ / $>
x = $ fromJust $ Map.lookup km
hack
通过使用quasiquotes并提取源文件名的字符串,我设法破解了它。看来
Loc
没有Lift实例。有没有更好的方法? fromJustErr'l(Nothing)=
error $ printf[internal] fromJust error \
\\\\
(在文件%s中)l
fromJustErr'l(Just x)= x
fromJustErr = do
l < - location
让fn = loc_filename l
fnl :: Q Exp = TH.lift fn
[| fromJustErr'$ fnl |]
谢谢!
< (我知道通过 Maybe
函数可以比 fmap
更好,而不是使用 fromJust
,但我有时需要破解。)
这里试图让这个模式更加可重用。
$ b 关键的想法是将一个自定义的错误
传递给我们的函数,该函数将包含错误消息中的位置。您可以像这样使用它:
fromJust'::(String - > a) - >也许是 - >一个
fromJust'的错误Nothing =错误from just nothing nothing!
fromJust'error(Just x)= x
fromJust :: Q Exp
fromJust = withLocatedError [| from''']
使用此函数与您的原始方法类似:
main = print(1 + $ fromJust Nothing)
$
$ b
withLocatedError :: Q Exp - >现在,对于使这项工作成功的模板Haskell:
withLocatedError :: Q Exp - > Q Exp
withLocatedError f = do
let error = locatedError =<<位置
appE f错误
位置错误:: Loc - > Q Exp
locatedError loc = do
let postfix =at++ formatLoc loc
[| \msg - >错误(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
产生定制的错误
函数,给定一个位置。 withLocatedError
将此内容反馈给 fromJust'
以将所有内容挂钩在一起。 formatLoc
只是很好地将位置格式化为一个字符串。
运行这个程序给了我们想要的结果:
FromJustTest:fromJust nothing nothing!在FromJustTest.hs:5:19
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:
fromJust' :: (String -> a) -> Maybe a -> a
fromJust' error Nothing = error "fromJust got Nothing!"
fromJust' error (Just x) = x
fromJust :: Q Exp
fromJust = withLocatedError [| fromJust' |]
Using this function is similar to your original approach:
main = print (1 + $fromJust Nothing)
Now, for the Template Haskell that makes this work:
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
produces the customized error
function, given a location. withLocatedError
feeds this to fromJust'
to hook everything together. formatLoc
just formats the location nicely into a string.
Running this gives us the result we wanted:
FromJustTest: fromJust got Nothing! at FromJustTest.hs:5:19
这篇关于有什么正确的方法让模板haskell包装一个带有源信息的函数(例如行号)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!