Come gestisci specifiche eccezioni di rete in Haskell?

4

Ho i seguenti elementi per provare a connettermi a un server:

testAddress :: HostName -> Int -> IO (Maybe Handle)
testAddress host iPort = do
    let port = PortNumber $ fromIntegral iPort
    putStrLn $ "Testing - Host: " ++ host ++ ", Port: " ++ show iPort
    result <- try $ connectTo host port
    case result of
        Left (SomeException e) -> return Nothing
        Right h -> do
            putStrLn $ "Connected to " ++ host
            return $ Just h

Ho fatto l'eccezione per catturare "SomeException", ma so che non è il modo corretto per farlo; poiché catturerà tutto e non potrai gestire singoli casi. Non riesco però a trovare i nomi di specifiche eccezioni di rete. Non sembra esserci alcuna documentazione per il pacchetto di rete, e ogni esempio che posso trovare su google utilizza solo "SomeException". Se provo a connettermi a un host e una porta casuali e non provo a rilevare nulla, ottengo l'errore: " * Eccezione: connect: failed (Timeout della connessione (WSAETIMEDOUT))" Ma non sembra darmi il nome esatto dell'eccezione da provare e catturare. Ho pensato che potesse essere "WSAETIMEOUT", ma quando ho provato a capirlo, ho ricevuto un errore di compilazione dicendo che non riusciva a trovare il costruttore per "WSAETIMEOUT". Cosa dovrei fare. Non voglio prendere tutto e trattarlo allo stesso modo, perché poi non so che cosa sta succedendo.

Grazie

    
posta Carcigenicate 24.07.2014 - 03:54
fonte

2 risposte

3

Puoi eseguire la corrispondenza del modello su un tipo di eccezione specifico come questo:

testAddress :: HostName -> Int -> IO (Maybe Handle)
testAddress host iPort = do
    let port = PortNumber $ fromIntegral iPort
    putStrLn $ "Testing - Host: " ++ host ++ ", Port: " ++ show iPort
    result <- try $ connectTo host port
    case result of
        Left (e :: MyExceptionType) -> return Nothing
        Right h -> do
            putStrLn $ "Connected to " ++ host
            return $ Just h

In questo modo, Haskell dedurrà che il tipo di result è Either MyExceptionType Handle , e try pertanto rileverà solo eccezioni di MyExceptionType , propagando tutti gli altri invariati.

Come per i particolari tipi di eccezioni usati dal pacchetto network , non sono riuscito a trovare alcuna documentazione su di essi, ma poiché Typeable è una superclasse di Exception , dovresti essere in grado di stampare il tipo di ogni eccezione che si cattura, che dovrebbe essere utile.

    
risposta data 24.07.2014 - 17:55
fonte
1

Dopo aver saltato i cerchi, questa è la mia soluzione finale (tutt'altro che perfetta):

data NetException = NetNoException | NetTimeOut | NetRefused | NetHostUnreach
                    | NetANotAvail
                    deriving (Show, Eq)

diffExcept :: Either SomeException Handle -> Either NetException Handle
diffExcept (Right h) = Right h
diffExcept (Left (SomeException m))
    | err == "WSAETIMEDOUT" = Left NetTimeOut
    | err == "WSAECONNREFUSED" = Left NetRefused
    | err == "WSAEHOSTUNREACH" = Left NetHostUnreach
    | err == "WSAEADDRNOTAVAIL" = Left NetANotAvail
    | otherwise = error $ show m
    where
        err = reverse . dropWhile (== ')') . reverse . dropWhile (/='W') $ show m

Quindi l'errore dovrà essere passato a diffExcept, quindi il risultato di questo può essere confrontato con il modello.

Si noti che questo non è così sicuro nella sua forma attuale. Supponendo che tutti gli errori inizieranno con una "W" (tutti gli errori di rete sembrano finora) e il messaggio terminerà solo in ")". Chiunque usi questo dovrebbe probabilmente risolverlo prima, ma dà l'idea generale.

    
risposta data 24.07.2014 - 18:12
fonte

Leggi altre domande sui tag