I wrote a series of posts while returning to my own studies of the types Either and EitherT . You can read it here: http://watchchrislearn.com/blog/2013/12/01/working-entirely-in-eithert/
I use the errors package to get a bunch of nice helpers using the EitherT functions ( left and right , for example, to return canceled versions of left and right ).
By extracting your potential failure conditions into your own helpers, you can make the main line of your code read completely sequentially, without checking the results of case checks.
From this post you can see how the runEitherT section is a sequential piece of work, but simply has EitherT crash EitherT . Obviously, this code is pretty tricky to show how MaybeT plays inside EitherT . In real code, this will be just the story you wanted to tell, with one left / right at the end.
import Control.Error import Control.Monad.Trans -- A type for my example functions to pass or fail on. data Flag = Pass | Error main :: IO () main = do putStrLn "Starting to do work:" result <- runEitherT $ do lift $ putStrLn "Give me the first input please:" initialText <- lift getLine x <- eitherFailure Error initialText lift $ putStrLn "Give me the second input please:" secondText <- lift getLine y <- eitherFailure Pass (secondText ++ x) noteT ("Failed the Maybe: " ++ y) $ maybeFailure Pass y case result of Left val -> putStrLn $ "Work Result: Failed\n " ++ val Right val -> putStrLn $ "Work Result: Passed\n " ++ val putStrLn "Ok, finished. Have a nice day" eitherFailure :: Monad m => Flag -> String -> EitherT String m String eitherFailure Pass val = right $ "-> Passed " ++ val eitherFailure Error val = left $ "-> Failed " ++ val maybeFailure :: Monad m => Flag -> String -> MaybeT m String maybeFailure Pass val = just $ "-> Passed maybe " ++ val maybeFailure Error _ = nothing
source share