Written by Chris Schneider
Using the Either monad inside another monad
After yesterday’s post about the
I wanted to see if it was easy to embed that bit of
doWork stuff right
into the main function.
This was mostly about learning the syntax, I would suggest keeping stuff separate as much as possible in real code.
The biggest gotcha I found was that the indentation of the
eitherFailure... bit needed to be deeper than the
r in the
This ended up being more than my normal 2 space indent.
import Control.Error -- A type for my example functions to pass or fail on. data Flag = Pass | Error main :: IO () main = do putStrLn "Starting to do work:" -- The inner monad here is Either. But note that we have -- no IO ability inside of it. let result = do x <- eitherFailure Pass "Initial Thing" y <- eitherFailure Error ("Second Thing " ++ x) note ("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" -- Simple function that we can use to force it to error out with a Left, or -- pass with a Right value. It just includes some helper text as its content, -- showing what happened. eitherFailure :: Flag -> String -> Either String String eitherFailure Pass val = Right $ "-> Passed " ++ val eitherFailure Error val = Left $ "-> Failed " ++ val -- Simlar to eitherFailure, but return a (Just String) or a Nothing based on -- if we told it to fail. maybeFailure :: Flag -> String -> Maybe String maybeFailure Pass val = Just $ "-> Passed maybe " ++ val maybeFailure Error _ = Nothing
You can see it’s the same code, except the
result in main is calculated
directly there, rather than calling another function.
Note that this isn’t the transformer library, so you can’t be clever and do
lift and friends to do IO in that Either workflow.