On 2/4/07, Martin Huschenbett <[EMAIL PROTECTED]> wrote:
Hi,

I've often got the same pattern with nested Maybes but inside the IO
monad (sure this could be every other monad too). Assuming that I've got
functions:

This is where my favorite part of the mtl steps in: monad transformers.

First, we'll create a transformed version of the IO monad, which
encompasses the idea of failure.  I've made the failures somewhat more
general by allowing String typed error messages, but you can replace
String with whatever type you'd like (including () if you really don't
want any such information).

newtype MyIO a = MyIO { runMyIO :: ErrorT String IO a }
    deriving (Functor, Monad, MonadError String)

This uses GHC's newtype deriving mechanism, and thus requires
-fglasgow-exts.  The same effect can be achieved in Haskell 98 by
using a type synonym instead of a newtype.

Then, we need to have your operations produce their results in MyIO a
instead of IO (Maybe a):

getInput :: MyIO Input
processInput :: Input -> MyIO Result
printError :: String -> MyIO ()
printResult :: Result -> MyIO ()

Finally, we can rewrite your main function without the case statements:

main = runErrorT . runMyIO $
    (do input <- getInput
        result <- processInput input
        printResult result)
    `catchError` printError

However, in this case you don't really need do notation at all.  You
have a very nice pipeline of operations, and we can express it that
way:

main' = runErrorT . runMyIO $ (getInput >>= processInput >>= printResult)
                              `catchError` printError

which should remove the last vestiges of imperative-feeling code.

/g

--
It is myself I have never met, whose face is pasted on the underside of my mind.
_______________________________________________
Haskell-Cafe mailing list
[email protected]
http://www.haskell.org/mailman/listinfo/haskell-cafe

Reply via email to