String

Error

Either

MonadError

import Control.Monad.Error -- suppose you have a function like: parseRomanNumeral :: String → Either String Int parseRomanNumeral input = -- code here; result in either (Left "parse error message") or (Right somenumber) -- equivalently, either (throwError "parse error message") or (return somenumber) -- then you can use the monad like this: addRoman :: String → String → Either String Int addRoman a b = do inta ← parseRomanNumeral a intb ← parseRomanNumeral b return (a + b)

addRoman

Left

Right

loadConfigFile :: FilePath → IO (Either String Config) loadConfigFile path = do contents ← readFile path -- parse parse parse. -- errors are: return (Left err) -- success is: return (Right ok) -- (again can use "throwError", but the success case then looks like -- return (return ok), which is sorta crazy) -- now imagine loading two config files: loadTwo :: IO (Either String (Config, Config)) loadTwo = do maybeconfig ← loadConfigFile "foo" case maybeconfig of Left err → return (Left err) Right foo → do maybeconfig ← loadConfigFile "bar" case maybeconfig of -- yuck! I won't even finish this

addRoman

ErrorT

loadConfigFile' :: FilePath → ErrorT String IO Config loadConfigFile' path = do contents ← liftIO $ readFile path -- plain "throwError" and "return ok" now work here. loadTwo' :: IO (Either String (Config, Config)) loadTwo' = runErrorT $ do foo ← loadConfigFile' "foo" bar ← loadConfigFile' "bar" return (foo, bar)

loadConfigFile

runErrorT

Either

IO

ErrorT

IO (Either String a)

ErrorT String IO a

loadConfigFile

loadTwo'' :: IO (Either String (Config, Config)) loadTwo'' = runErrorT $ do foo ← ErrorT $ loadConfigFile "foo" bar ← ErrorT $ loadConfigFile "bar" return (foo, bar)

In circumstances where it makes sense, you can leave functions out of the ErrorT monad. Then, when combining them, wrap plain IO calls with liftIO , the IO (Either ...) calls with ErrorT , and the whole block in runErrorT .

Either

loadTwo''

num <- ErrorT $ return $ parseRomanNumeral "iix"

return

Either

IO (Either ...)

ErrorT

ErrorT

Here's a Haskell trick that took me a while to figure out but that I use all the time. First, the error monad: lets you sequence operations that may fail with error messages. There are a bunch of different types and type classes available so it's pretty general, but the one I always end up using isas mytype andas myinstance. Here's a contrived example:If either of those parses fail, then the result ofiswith the error. Otherwise, success is again. Hopefully you can see this composes easily.Ok, more background: you'll often mix this with IO. For example:It'd be nice to again compose these like I did in. That's what themonad transformer is for. Rewriting the above to use it, with the new bits underlined:This is much closer to what you're trying to express. The monad is letting you say: "first load the file foo, and stop here and return if there's an error. then, ...".All that was background. Here's the trick.I had to change the type ofso it would be fed into. That was ok in the above example, maybe, because the code ended up clearer. But what about code that you don't control, that has the old type with annested inside an? Simple: theconstructor exactly convertsinto. So I could've used the originaland just written the second function like this:In summary, the basic pattern is:Final trick: you can even use non-IO-using plains here, too. WithinThebrings theinto, then theconverts it into anWhenever code gets this hairy, though, the real consideration is that you're composing layers at the wrong abstractions and you should restructure it.