2012-05-14 11 views
12

estoy leyendo captación de aguas pluviales, y he llegado al capítulo 9. Se introduce el siguiente fragmento de código:La función "mango" y Real World Haskell

import System.IO 
import Control.Exception 

saferFileSize :: FilePath -> IO (Maybe Integer) 
saferFileSize path = handle (\_ -> return Nothing) $ do 
    h <- openFile path ReadMode 
    size <- hFileSize h 
    hClose h 
    return (Just size) 

No se compilará sin embargo, dar el siguiente mensaje de error:

test.hs:5:22: 
    Ambiguous type variable `e0' in the constraint: 
     (Exception e0) arising from a use of `handle' 
    Probable fix: add a type signature that fixes these type variable(s) 
    In the expression: handle (\ _ -> return Nothing) 
    In the expression: 
     handle (\ _ -> return Nothing) 
     $ do { h <- openFile path ReadMode; 
      size <- hFileSize h; 
      hClose h; 
      return (Just size) } 
    In an equation for `saferFileSize': 
     saferFileSize path 
      = handle (\ _ -> return Nothing) 
      $ do { h <- openFile path ReadMode; 
        size <- hFileSize h; 
        hClose h; 
        .... } 

¿Qué está mal aquí? ¿Por qué no compilará?

Respuesta

25

No mucho tiempo después de la captación de aguas pluviales salió, la interfaz de excepción fue cambiado a apoyar los manipuladores más flexibles donde el tipo del manejador determina qué excepciones atrapará. P.ej. un controlador que tiene SomeException cogerá nada (no suele ser una buena idea), mientras que un controlador que lleva IOException sólo capturar las excepciones IO.

Como consecuencia de esto, es fácil encontrar problemas de ambigüedad con manejadores de "no hacer nada" como el de su ejemplo, ya que el compilador no puede deducir qué tipo de excepciones está tratando de detectar. Una manera fácil de solucionar esto es proporcionar una firma de tipo para su función de controlador.

handle ((\_ -> return Nothing) :: IOException -> IO (Maybe Integer)) $ do ... 

Sin embargo, esto puede ser algo detallado. Una solución alternativa es especializarse handle.

handleIO :: (IOException -> IO a) -> IO a -> IO a 
handleIO = handle 

Entonces, sólo puede utilizar handleIO cada vez que desee controlar las excepciones IO, sin tener que deletrear la firma de tipo del controlador.

saferFileSize path = handleIO (\_ -> return Nothing) $ do ... 

Una tercera opción es utilizar la extensión ScopedTypeVariables, que (entre otras cosas) le permite proporcionar una anotación de tipo de sólo el argumento de una función, permitiendo que el resto se infiere.

{-# LANGUAGE ScopedTypeVariables #-} 
saferFileSize path = handle (\(_ :: IOException) -> return Nothing) $ do ... 
+0

La documentación de la función 'en asa en el sitio web de Haskell es muy claro acerca de esto (al menos a nivel de entrada de personas - los que necesitan documentación) https://wiki.haskell.org/Exception gracias por la explicación muy claro que el compilador sólo nos tiene que especificar los tipos de excepciones para controlar! – jocull

4

captación de aguas pluviales es bastante antiguo. La firma handle función ha cambiado en GHC 6,10 o menos.

Para utilizar la versión antigua, importe Control.OldException en lugar de Control.Exception`. Recibirá advertencias de depreciación pero el programa compilará.

O puede utilizar la nueva interfaz y dar al manejador de una firma explícita, así:

((\ _ -> return Nothing) :: IOException -> IO (Maybe Integer)) 
Cuestiones relacionadas