
* Simon Marlow
On 06/09/2012 11:05, Roman Cheplyaka wrote:
* Herbert Valerio Riedel
[2012-09-06 11:40:23+0200] Hello,
while reading over the source code of network[1], I noticed a use of 'throw' where I'd expect 'throwIO':
import qualified Control.Exception as Exception
catchIO :: IO a -> (Exception.IOException -> IO a) -> IO a catchIO = Exception.catch
-- Returns the first action from a list which does not throw an exception. -- If all the actions throw exceptions (and the list of actions is not empty), -- the last exception is thrown. firstSuccessful :: [IO a] -> IO a firstSuccessful [] = error "firstSuccessful: empty list" firstSuccessful (p:ps) = catchIO p $ \e -> case ps of [] -> Exception.throw e _ -> firstSuccessful ps
...so, is `throw` used properly in the code above, or should it rather be `throwIO`?
[1]: http://hackage.haskell.org/packages/archive/network/2.3.1.0/doc/html/src/Net...
In this particular situation it doesn't matter.
If you use throwIO, then, if all actions fail, firstSuccesful will return a proper IO action which, when sequenced, throws an exception.
If you use throw, then in the same situation the result of firstSuccessful will throw an exception before yielding a proper IO value.
However, I agree with you that throwIO would be somewhat more idiomatic here. (And IIRC I wrote this code, so you can blame me.)
Here is some background reading:
http://hackage.haskell.org/trac/ghc/ticket/1171
The bottom line is that it's hard to tell what will happen if you use throw here. Always use throwIO if you can.
So, regarding this example, does it mean that, under some circumstances, `firstSuccessful [a]` can throw `error "firstSuccessful: empty list"`? Would you also advise changing `error` to `throwIO . ErrorCall` here? -- Roman I. Cheplyaka :: http://ro-che.info/