The important thing about exceptions is that if the action of IO a raises an exception, you will not get any value of a . Since the binding operator (>>=) :: Monad m => ma -> (a -> mb) -> mb from monads allows later actions to depend on the results of the previous ones, this means that we will not be able to perform the following actions after how do you fail.
If you have default values, you can use a ramp approach . However, from your example, it seems that you only care about the sequence of independent actions using the operator (>>) . You can make a monoid from this, but I think the simplest approach is to have a function that executes an IO () list of actions and collects any exceptions from the list:
import Control.Exception (SomeException, try) import Data.Either (lefts) exceptions :: [IO ()] -> IO [SomeException] exceptions = fmap lefts . mapM try
You will need to use an action list instead of a do notation, though:
> :{ | exceptions [ putStrLn "foo" | , throwIO DivideByZero | , putStrLn "bar" | , throwIO (IndexOutOfBounds "xyzzy") | ] | :} foo bar [divide by zero,array index out of range: xyzzy]
source share