5

假设我从一个函数开始

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

黑客

我确实设法通过使用准引号并解除源文件名的字符串来破解它。似乎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,但有时我需要破解。)

4

2 回答 2

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]

locatedErrorerror在给定位置的情况下生成自定义函数。withLocatedError把它喂到fromJust'把所有东西联系在一起。formatLoc只需将位置很好地格式化为字符串。

运行它会给我们想要的结果:

FromJustTest: fromJust got Nothing! at FromJustTest.hs:5:19
于 2011-08-16T11:33:50.263 回答
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- 但你想要一个通用的方式,这不是。

于 2011-08-16T05:16:11.317 回答