
J. Garrett Morris wrote:
This is where my favorite part of the mtl steps in: monad transformers.
I agree, the Error monad is very helpful here.
First, we'll create a transformed version of the IO monad,
Why go to the trouble of creating a new monad? The existing ones are fine. (While writing this, I just saw Bulat's posts. Nice!) It would be nicest if we had MaybeT available, as in http://www.haskell.org/haskellwiki/New_monads/MaybeT Then you could just write: import Control.Monad.Maybe main = runMaybeT $ doIt `mplus` liftIO printError where doIt = do input <- MaybeT getInput result <- MaybeT $ processInput input liftIO $ printResult result You could simplify things if you change the types from IO (Maybe a) to MaybeT IO a. Then you would have: main = runMaybeT $ doIt `mplus` liftIO printError where doIt = do input <- getInput result <- processInput input liftIO $ printResult result But you might want to do something more robust with the error reporting. Then you would do this: import Control.Monad.Error data MyError = InputError | OutputError | Unknown String instance Error MyError where noMsg = Unknown "Oops" strMsg x = Unknown x Then make the type of printError printError :: MyError -> IO () and we have: main = runErrorT $ doIt `catchError` (liftIO . printError) where doIt = do input <- liftIO getInput >>= maybe (throwError InputError) return result <- liftIO (processInput input) >>= maybe (throwError OutputError return liftIO $ printResult result Again, you can simplify things if you do change the types, using ErrorT MyError IO a in place of IO (Maybe a), etc., and put the throwError calls inside the functions. main = runErrorT $ doIt `catchError` (liftIO . printError) where doIt = do input <- getInput result <- processInput input liftIO $ printResult result Regards, Yitz