Вот попытка сделать этот шаблон несколько более пригодным для повторного использования.
Основная идея состоит в том, чтобы передать в нашу функцию настроенный 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