Pregunta ¿Cómo rastrear el tipo de excepción no detectada?


Procedente de lenguajes JVM que generan un gigantesco seguimiento de la pila cuando no se detecta una excepción, me siento frustrado cuando veo algo como connect: does not exist (Connection refused) y nada más en la salida de mi programa y luego se cierra. Entiendo que alguna excepción fue levantada y no atrapada. Incluso esperaba que ocurriera una excepción, ya que traté de conectarme a un servidor fuera de línea. Así que todo lo que necesito es solo una forma de manejar esta excepción, pero lo que no entiendo es cómo se supone que debo averiguar qué tipo de esa excepción es hacer eso.

Lo que solía hacer hasta el día de hoy era simplemente buscar el mensaje específico en Google y revisar todos los archivos de la lista de correo o los archivos fuente en busca de información, pero ese no puede ser el enfoque correcto. Entonces, mi pregunta es como en el título:

¿Cómo rastrear el tipo de excepción no detectada?


5
2017-10-24 11:39


origen


Respuestas:


Puedes usar typeOf para imprimir el tipo de la excepción:

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

Ejemplo de salida

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

7
2017-10-24 13:55



Esta es realmente una de las peores partes de Haskell: es muy difícil obtener rastros de pila.

La forma más directa es compilar el programa para crear perfiles y luego invocarlo con la opción RTS

myprog +RTS -xc -RTS

que arrojará un rastro de pila, aunque he oído que es un poco problemático y puede que no funcione bien. Este es el ejemplo de la documentación

*** 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

He ido tan lejos como para grepping la fuente de cadenas de error particulares, sin embargo, cuando -xc no proporcionó suficiente información adicional

Si tiene una excepción que no se puede descifrar a través de una biblioteca en particular y desea manejarlo de una manera más pura, puede usar las funciones de spoon paquete para convertirlo en un puro Maybe resultado. Desde allí puede volver a subirlo a través de sus propias excepciones. Eso puede hacer que el error sea más fácil de manejar también.


4
2017-10-24 11:48



Si todo lo que necesitas es el tipo, ¿por qué no usarlo? tipo de? Todas las excepciones deben ser instancias de Typeable.


4
2017-10-24 13:47



Me gusta la respuesta de J. Abrahamson, pero si eso falla o si desea una alternativa ... Escribo temporalmente un controlador que detecta "todas" las excepciones, solo para imprimir el nombre de la excepción. Una vez que tengo eso, modifico el controlador de excepciones para tratar solo las excepciones que puedo manejar.

Pero lee el advertencia sobre "Capturar todas las excepciones"


EDITAR: Aquí hay un código de muestra:

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

1
2017-10-24 11:54