Reputation: 11982
I would like to combine the Error Monad and the IO Monad in Haskell. Here is an excerpt from my code:
type AskMonad = ErrorT String IO
askSomething :: AskMonad Direction
askSomething = do
liftIO $ putStrLn "Choose an element from the list [1,2,3,4]"
input <- liftIO getLine
let entry = read input :: Int
if entry `elem` [1,2,3,4]
then return $ toEnum entry -- from Int to Direction
else throwError "Invalid input!"
selectMove :: [Player] -> Board -> IO (Direction, Position)
selectMove players board = do
direction <- runErrorT (askSomething) `catchError` --What to put here???
-- Other IO stuff...
I would like to achieve the following behavior:
askSomething
succeeds, get the Direction
.askSomething
fails, show
the error and run askSomething
again.However, I don't know what to put as the second argument of catchError
in order to get this behavior. I think it should be of the following type signature: Either String Direction -> AskMonad Direction
, but how can I access the computation that needs to be rerun (askSomething
in this case).
Upvotes: 1
Views: 77
Reputation: 4540
The code as you have it now seems like it would be trying to catch exceptions not represented in the ErrorT String
result. My thought is that you are actually looking to retry if runErrorT
results in a Left
value (an "expected" exception). In that case, something like this retryForever
may work:
retryForever :: AskMonad a -> IO a
retryForever action =
runErrorT action >>= either (\ex -> putStrLn ex >> retryForever action) return
which could be used like:
direction <- retryForever askSomething
P.S. I believe ErrorT
was deprecated in favor of ExceptT
, and that ExceptT
is only more general so the transition should be trivial if you decide to switch.
Upvotes: 2