¿Cuándo uso qué función?
Aquí está la recomendación de la documentación de Control.Exception:
- Si usted quiere hacer algo de limpieza en caso de que se produce una excepción, utilizar
finally, bracketo onException.
- Para recuperarse después de una excepción y hacer otra cosa, la mejor opción es utilizar uno de la
tryfamilia.
- ... a menos que se esté recuperando de una excepción asincrónica, en cuyo caso use
catcho catchJust.
intente :: Excepción e => IO a -> IO (cualquiera de los dos)
tryrealiza una IOacción para ejecutarse y devuelve un Either. Si el cálculo tuvo éxito, el resultado se entrega envuelto en un Rightconstructor. (Piense bien en lugar de mal). Si la acción arrojó una excepción del tipo especificado , se devuelve en un Leftconstructor. Si la excepción no fue del tipo apropiado, continúa propagándose hacia arriba en la pila. Especificar SomeExceptioncomo tipo detectará todas las excepciones, lo que puede ser una buena idea o no.
Tenga en cuenta que si desea capturar una excepción de un cálculo puro, tendrá que usar evaluatepara forzar la evaluación dentro de 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
catch :: Exception e => IO a -> (e -> IO a) -> IO a
catches similar a try. Primero intenta ejecutar la IOacción especificada , pero si se lanza una excepción, el controlador 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, existe una diferencia importante. Cuando se usa, catchsu controlador no puede ser interrumpido por una excepción asincrónica (es decir, arrojado desde otro hilo a través de throwTo). Los intentos de generar una excepción asincrónica se bloquearán hasta que su controlador haya terminado de ejecutarse.
Tenga en cuenta que hay algo diferente catchen el Preludio, por lo que es posible que desee hacerlo import Prelude hiding (catch).
handle :: Exception e => (e -> IO a) -> IO a -> IO a
handlees simplemente catchcon los argumentos en orden inverso. Cuál usar depende de lo que hace que su código sea más legible, o cuál encaja mejor si desea usar una aplicación parcial. Por lo demás, son idénticos.
tryJust, catchJust y handleJust
Tenga en cuenta que try, catchy handlecogerá todas las excepciones del tipo especificado / inferido. tryJusty amigos le permiten especificar una función de selección que filtra qué excepciones desea manejar específicamente. Por ejemplo, todos los errores aritméticos son de tipo ArithException. Si solo quiere atrapar DivideByZero, 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 solo puede ocurrir en código impuro (es decir, la IOmónada). Si necesita manejar errores en código puro, debería considerar devolver valores usando Maybeo en su Eitherlugar (o algún otro tipo de datos algebraicos). Esto suele ser preferible, ya que es más explícito para que siempre sepa qué puede suceder y dónde. Monads like Control.Monad.Errorhace que este tipo de manejo de errores sea más fácil de trabajar.
Ver también: