[Haskell-cafe] Re: nested maybes

J. Garrett Morris trevion at gmail.com
Sun Feb 4 19:01:05 EST 2007


On 2/4/07, Martin Huschenbett <huschi at gmx.org> 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.


More information about the Haskell-Cafe mailing list