Cuando Cómo puedo utilizar que funcionan?
Aquí está la recomendación de la documentación Control.Exception:
- Si usted quiere hacer algo de limpieza en caso de que se produce una excepción, utilizar
finally
, bracket
o onException
.
- Para recuperar después de una excepción y hacer otra cosa, la mejor opción es usar una de la familia
try
.
- ... a menos que se esté recuperando de una excepción asincrónica, en cuyo caso use
catch
o catchJust
.
intento :: Exception e => IO a -> IO (O e a)
try
toma una acción IO
para funcionar, y devuelve un Either
. Si el cálculo tuvo éxito, el resultado se da en un constructor Right
. (Piensa en lo correcto en lugar de lo incorrecto). Si la acción arrojó una excepción del tipo especificado, se devuelve en un constructor Left
. Si la excepción fue no del tipo apropiado, continúa propagándose en la pila. Especificando SomeException
como el tipo captará todas las excepciones, lo que puede o no ser una buena idea.
Tenga en cuenta que si desea capturar una excepción de un cálculo puro, tendrá que usar evaluate
para forzar la evaluación dentro del try
.
main = do
result <- try (evaluate (5 `div` 0)) :: IO (Either SomeException Int)
case result of
Left ex -> putStrLn $ "Caught exception: " ++ show ex
Right val -> putStrLn $ "The answer was: " ++ show val
captura :: Exception e => IO a -> (e -> IO a) -> IO a
catch
es similar a try
. Primero intenta ejecutar la acción IO
especificada, pero si se lanza una excepción, el manejador recibe la excepción para obtener una respuesta alternativa.
main = catch (print $ 5 `div` 0) handler
where
handler :: SomeException -> IO()
handler ex = putStrLn $ "Caught exception: " ++ show ex
Sin embargo, hay una diferencia importante. Al usar catch
, su controlador no puede ser interrumpido por una excepción asincrónica (es decir, lanzada desde otro hilo a través del throwTo
). Los intentos de generar una excepción asincrónica se bloquearán hasta que el controlador haya terminado de ejecutarse.
Tenga en cuenta que hay un catch
diferente en el Preludio, por lo que es posible que desee hacer import Prelude hiding (catch)
.
mango :: Exception e => (e -> IO a) -> IO a -> IO a
handle
es simplemente catch
con los argumentos en el orden inverso. Cuál usar depende de qué hace que su código sea más legible, o cuál se ajusta mejor si desea usar una aplicación parcial. Son por lo demás idénticos.
tryJust, catchJust y handleJust
Tenga en cuenta que try
, catch
y handle
cogerá todos excepciones del tipo especificado/inferido. tryJust
y sus amigos le permiten especificar una función de selector que filtra qué excepciones desea específicamente manejar. Por ejemplo, todos los errores aritméticos son del tipo ArithException
.Si sólo se desea capturar DivideByZero
, que puede hacer:
main = do
result <- tryJust selectDivByZero (evaluate $ 5 `div` 0)
case result of
Left what -> putStrLn $ "Division by " ++ what
Right val -> putStrLn $ "The answer was: " ++ show val
where
selectDivByZero :: ArithException -> Maybe String
selectDivByZero DivideByZero = Just "zero"
selectDivByZero _ = Nothing
Una nota sobre la pureza
Tenga en cuenta que este tipo de manejo de excepciones sólo puede ocurrir en el código impuro (es decir, el IO
mónada). Si necesita manejar los errores en código puro, debe buscar los valores de retorno usando Maybe
o Either
(o algún otro tipo de datos algebraicos). Esto a menudo es preferible, ya que es más explícito, por lo que siempre sabrá qué puede pasar. Las mónadas como Control.Monad.Error
facilitan el manejo de este tipo de errores.
Consulte también:
Re: 3 - lea el [fino manual] (http://hackage.haskell.org/packages/archive/base/latest/doc/html/Control-Exception-Base.html): [handle - A version de captura con los argumentos intercambiados; útil en situaciones donde el código para el controlador es más corto] (http://hackage.haskell.org/packages/archive/base/latest/doc/html/Control-Exception-Base.html#v:handle). –