Cat Dancer wrote: > I have a program that performs a series of IO operations, each which > can result in an error or a value. If a step returns a value I > usually want to pass that value on to the next step, if I get an error > I want to do some error handling but usually want to skip the > remaining steps.
> Thus I have a lot of functions with return types like IO (Either > String x), where x might be (), Integer, or some other useful value > type, and a lot of case statements like You are on the right track. The point is that (IO (Either String a)) is a Monad, too. This allows you to write the ever repeating case statements once and forall: newtype ErrorIO a = ErrorIO (IO (Either String a)) instance Monad ErrorIO where return x = return (Right x) f >>= g = do ex <- f case ex of e@(Left _) -> return e Right x -> g x It happens that you can parametrize this on IO: newtype ErrorT m a = ErrorT (m (Either String a)) type ErrorIO a = ErrorT IO a instance Monad m => Monad (ErrorT m) where ... -- same as above And you just rediscovered monad transformers. Regards, apfelmus PS: In the special case of IO, you can also use exceptions. But using ErrorT is better style. _______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe