El tipo de Control.Exception.handle
es:
handle :: Exception e => (e -> IO a) -> IO a -> IO a
El problema que estamos viendo es que la expresión lambda (\_ -> return "err")
no es de tipo e -> IO a
donde e
es una instancia de Exception
. ¿Claro como el barro? Bueno. Ahora voy a ofrecer una solución que en realidad debería ser útil :)
Lo que pasa es que en su caso e
debería ser Control.Exception.ErrorCall
desde undefined
utiliza error
que arroja ErrorCall
(una instancia de Exception
).
Para manejar usos de undefined
puede definir algo como handleError
:
handleError :: (ErrorCall -> IO a) -> IO a -> IO a
handleError = handle
Básicamente se trata de un alias Control.Exception.handle
con e
fijados según ErrorCall
que es lo que error
tiros.
Parece que este cuando se ejecuta en GHCi 7.4.1:
ghci> handleError (\_ -> return "err") undefined
"err"
Para manejar todas las excepciones en función handleAll
se puede escribir de la siguiente manera:
handleAll :: (SomeException -> IO a) -> IO a -> IO a
handleAll = handle
La captura todas las excepciones tiene consecuencias bien descrito en este extracto de la documentación Control.Exception
:
La captura de todas las excepciones
Es posible capturar todas las excepciones, utilizando el tipo de SomeException
:
catch f (\e -> ... (e :: SomeException) ...)
Sin embargo, esto no es normalmente lo que quieres hacer!
Por ejemplo, supongamos que desea leer un archivo, pero si no existe, continúe como si contuviera ""
. Es posible que sienta la tentación de atrapar todas las excepciones y devolver ""
en el controlador. Sin embargo, esto tiene todo tipo de consecuencias indeseables. Por ejemplo, si el usuario presiona el control C en el momento justo, se capturará la excepción UserInterrupt
, y el programa continuará ejecutándose bajo la creencia de que el archivo contiene ""
. De forma similar, si otro subproceso intenta matar el subproceso que lee el archivo, se ignorará la excepción ThreadKilled
.
En su lugar, solo debe detectar exactamente las excepciones que realmente desea. En este caso, esto probablemente sería más específico que incluso "cualquier excepción IO"; un error de permisos probablemente también desee ser manejado de manera diferente. En su lugar, es probable que desee algo como:
e <- tryJust (guard . isDoesNotExistError) (readFile f)
let str = either (const "") id e
Hay ocasiones cuando realmente necesita para recoger cualquier tipo de excepción. Sin embargo, en la mayoría de los casos esto es solo para que pueda hacer un poco de limpieza; usted no está realmente interesado en la excepción en sí misma.Por ejemplo, si abre un archivo, quiere volver a cerrarlo, ya sea que el procesamiento del archivo se ejecute normalmente o genere una excepción. Sin embargo, en estos casos puede usar funciones como bracket
, finally
y onException
, que en realidad nunca le pasan la excepción, pero solo llame a las funciones de limpieza en los puntos apropiados.
Pero a veces realmente es necesario detectar cualquier excepción, y realmente ver cuál es la excepción. Un ejemplo es en el nivel superior de un programa, es posible que desee detectar cualquier excepción, imprimirlo en un archivo de registro o en la pantalla, y luego salir con gracia. Para estos casos, puede usar catch
(o una de las otras funciones de captura de excepciones) con el tipo SomeException
.
Fuente: http://www.haskell.org/ghc/docs/latest/html/libraries/base/Control-Exception.html#g:4
¿Por qué el compilador necesita saber qué excepción? La función maneja todos los tipos de la clase. – luntain
Debido al tipo de 'handle'; cualquier uso de 'handle' debe aplicarse a * un * tipo particular de la clase Exception. Como su manejador funciona para todos los tipos en la clase, no hay forma de que el compilador asigne un tipo a 'handle'. (La 'e' viene del tipo de' handle'). –
Si usa la extensión ScopedTypeVariables puede simplemente 'manejar (\ (_ :: SomeException) -> return' err ') undefined'. – porges