data Error = Coder'error String | IO'error | Format'error String newtype EMonad a = EM { runEM :: IO (Either Error a) } instance Monad EMonad where ... left :: Error -> EMonad a left e = EM (return (Left e)) if'left :: EMonad a -> (Error -> EMonad a) -> EMonad a if'left (EM p) h = EM (p >>= either (runEM . h) (return . Right)) read'line :: EMonad String read'line = ... write'line :: String -> EMonad () write'line s = ... newtype UID = UID String deriving Show validate :: String -> EMonad UID validate s | not (null s) && all isDigit s = return (UID s) | otherwise = left (Format'error s) read'record :: EMonad (String, UID) read'record = do name <- read'line uid <- read'line >>= validate return (name, uid) primary :: EMonad () primary = do x <- read'record write'line ("found record " ++ show x) `if'left` \e -> case e of Format'error s -> write'line ("format error in " ++ s) _ -> left e
Orthodox doctrine on Either:
Format'error
from validate
(requires javascript)
Exceptions for control flow…, David R. MacIver, blog
Compiling Exceptions Correctly, Graham Hutton and Joel Wright, Mathematics of Program Construction 2004.
I have more Haskell Notes and Examples