import Control.Monad.Error
import Control.Monad.Trans (lift)


data MyError = U0 | U1 | Other deriving (Eq, Read, Show)


instance Error MyError where
  noMsg    = Other
  strMsg _ = Other






foo = do lift (putStrLn "foo")
         mapM_ (\toThrow -> bar toThrow                      
                              `catchError` \caught ->        
                                                             
                                 case caught of U0 -> lift (putStrLn "foo caught U0")
                                                _  -> throwError caught)
               [U0, U1]                                      


bar toThrow = do lift (putStrLn " bar")
                 baz toThrow

baz toThrow = do lift (putStrLn "  baz")
                 throwError toThrow




main = do result <- runErrorT foo
          case result of
            Left e  -> putStrLn ("Caught error at top level: " ++ show e)
            Right v -> putStrLn ("Return value: " ++ show v)