2013-10-24 4 views
5

Исходя из языков JVM, которые выводят трассировку стека мамонта всякий раз, когда исключение не получается, я чувствую себя разочарованным, когда вижу что-то вроде connect: does not exist (Connection refused) и ничего больше в выходе моей программы, а затем закрывается. Я понимаю, что какое-то исключение подняли и не поймали. Я даже ожидал, что произойдет исключение, поскольку я попытался подключиться к автономному серверу. Так что все, что мне нужно - это просто способ справиться с этим исключением, но я не понимаю, как я должен узнать, какой тип этого исключения должен сделать это.Как отслеживать тип неперехваченного исключения?

То, что я обычно делал по сей день, было просто Google для конкретного сообщения и копать все архивы почтовых списков или исходные файлы в поисках информации, но это не может быть правильным подходом. Итак, у меня вопрос, как в названии:

Как отслеживать тип неперехваченного исключения?

+0

Обычно нужно напечатать тип исключения. Но как это поможет вам в этом случае? Сообщение совершенно ясное, не так ли? – Ingo

+2

Мне нужно написать 'catch' против определенного типа исключения. В этом сообщении нет полезной информации. –

ответ

7

Вы можете использовать typeOf для печати типа исключения:

import Data.Typeable 
import Control.Exception 
import System.IO.Error 

blackbox1 :: IO() 
blackbox1 = throw $ mkIOError doesNotExistErrorType "blackbox1" Nothing (Just "evil") 

blackbox2 :: IO() 
blackbox2 = throw DivideByZero 

traceExceptionName :: IO() -> IO() 
traceExceptionName act = act `catch` \(SomeException e) -> do 
    let rep = typeOf e 
     tyCon = typeRepTyCon rep 
    putStrLn $ "## Exception: Type " ++ show rep ++ " from module " ++ tyConModule tyCon ++ " from package " ++ tyConPackage tyCon 
-- throw e -- Rethrow exception. 

main :: IO() 
main = do 
    traceExceptionName blackbox1 
    traceExceptionName blackbox2 

Пример вывод

$ runhaskell ./main.hs    
## Exception: Type IOException from module GHC.IO.Exception from package base 
## Exception: Type ArithException from module GHC.Exception from package base 
+1

Можно ли использовать 'TypeRep' для получения дополнительной информации о пакете или модуле, определяющем конкретные исключения? –

+1

@ J.Abrahamson Да, я обновил свой ответ, чтобы включить эту информацию. – bennofs

+0

Очень круто, спасибо! –

4

Это действительно одна из самых худших частей Haskell - очень сложно получить следы стека из нее.

Самый прямой способ заключается в компиляции программы для профилирования затем вызвать его с помощью опции RTS

myprog +RTS -xc -RTS 

, который будет дамп трассировки стека, хотя я слышал, что это немного глючит и не может хорошо работать , Это пример из документации

*** Exception raised (reporting due to +RTS -xc), stack trace: 
    GHC.List.CAF 
    --> evaluated by: Main.polynomial.table_search, 
    called from Main.polynomial.theta_index, 
    called from Main.polynomial, 
    called from Main.zonal_pressure, 
    called from Main.make_pressure.p, 
    called from Main.make_pressure, 
    called from Main.compute_initial_state.p, 
    called from Main.compute_initial_state, 
    called from Main.CAF 

Я пошел, насколько источник оглавлению для конкретных строк ошибок, хотя, когда -xc не обеспечивают достаточную дополнительную информацию.

Если у вас есть неуловимое исключение, возникающее через определенную библиотеку, и вы хотите обработать его более чистым способом, вы можете использовать функции в пакете spoon, чтобы преобразовать его в чистый Maybe результат. Оттуда вы можете повторно поднять его по собственному усмотрению. Это может облегчить обработку ошибки.

+6

Существует также новая функция Debug.Trace.traceStack, которая похожа на Debug.Trace.trace, но также печатает трассировку стека вызовов, если она доступна. –

+0

Пробовал. В то время как это печатает, где возникло исключение, оно не печатает его тип. –

+0

@DonStewart Я не знал, что было там - захватывающе! –

1

Мне нравится ответ Дж. Абрахамсона, но если это терпит неудачу или вам нужна альтернатива ... Я временно пишу обработчик, который ловит «все» исключения, только для того, чтобы распечатать имя исключения. Как только я это сделаю, я модифицирую обработчик исключений, чтобы иметь дело только с исключениями, с которыми я могу справиться.

Но читать warning about "Catching all exceptions"


EDIT: Вот некоторые примеры кода:

catch XXXXXXX 
    (\e -> do 
    let err = show (e :: SomeException) 
    hPutStr stderr ("Warning: " ++ err) 
    return()) 
+0

Nifty! И кажется намного проще. Как выглядит ваш обработчик? –

+0

Я добавил несколько примеров кода. – mhwombat

+0

Он печатает то же самое в моем случае. I.e .: 'connect: не существует (соединение отклонено)'. Я подозреваю, что он ведет себя одинаково в других случаях, так как он использует экземпляр «Show». –

4

Если все, что вам нужно, это тип, то почему бы не использовать typeOf? Все исключения должны быть экземплярами Typeable.

Смежные вопросы