Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

I have the following to try and connect to a 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

I made the exception to catch "SomeException", but I know that's not the proper way to do it; as it will catch everything, and you can't handle individual cases. I can't find the names of specific network exceptions though. There doesn't appear to be any documentation for the Network package, and a every example I can find on google just uses "SomeException". If I try and connect to a random host and port, and I don't attempt to catch anything, I get the error: "* Exception: connect: failed (Connection timed out (WSAETIMEDOUT))" But it doesn't seem to give me the exact name of the exception to try and catch. I thought it might be "WSAETIMEOUT", but when I tried catching that, I got a compilation error saying that it couldn't find the constructor for "WSAETIMEOUT". What should I do. I don't want to just catch everything and treat it the same, because then I don't know whats going on.

Thank you

share|improve this question
1  
@Ptharien's Flame Control .Exception. It returns an IO Either. –  Carcigenicate Jul 24 '14 at 13:20
1  
And I found the documentation here: hackage.haskell.org/package/network-2.5.0.0/docs/Network.html but it's very bare. Nothing about exceptions, even though it throws them. –  Carcigenicate Jul 24 '14 at 14:04
1  
Thank you, and good luck. I'm fairly good with Google, and I can't find anything. The only thing left (that I literally just realized) was that I remember hearing that Haskell's Network module is basically just a port from a different language, and I haven't checked it's documentation yet. It's in a different language though, so I can't imagine the exception handling will be the same across the board. –  Carcigenicate Jul 24 '14 at 15:02
1  
I'll find the SO post. Someone was asking for network's documentation, and someone directed them elsewhere. Should be easy to find again. 2 seconds. –  Carcigenicate Jul 24 '14 at 15:04
1  
Maybe it's not a different language. I don't know what the "Berkeley Socket API" is from. stackoverflow.com/questions/3406998/… –  Carcigenicate Jul 24 '14 at 15:05

2 Answers 2

up vote 3 down vote accepted

You can pattern-match on a specific exception type like this:

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

This will actually cause Haskell to infer that the type of result is Either MyExceptionType Handle, and try will therefore only catch exceptions of MyExceptionType, propagating all others unchanged.

As for the particular exception types used by the network package, I couldn't find any documentation on them either, but since Typeable is a superclass of Exception, you should be able to print out the type of any exception you catch, which should be useful.

share|improve this answer
1  
Thanks. See my answer above. I'd like any feedback on how this could be made cleaner/safer. I'll accept your answer though, as there's no point in accepting mine. –  Carcigenicate Jul 24 '14 at 16:14
1  
pastebin.com/VNwrSAr3 All of it, although it won't compile as I don't have time to fill the cases. Thanks again. –  Carcigenicate Jul 24 '14 at 16:34

After jumping through hoops, this is my end solution (far from perfect):

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

So the error will have to be passed to diffExcept, then the result of that can be pattern matched against.

Note that this isn't that safe in it's current form. It's assuming that every error will start with a 'W' (all net errors seem to so far), and the message will end in only ')''s. Anyone using this should probably fix it up prior, but it gives the general idea.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.