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:
- if
askSomething
succeeds, get theDirection
. - if
askSomething
fails,show
the error and runaskSomething
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).
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 ifrunErrorT
results in aLeft
value (an "expected" exception). In that case, something like thisretryForever
may work:which could be used like:
P.S. I believe
ErrorT
was deprecated in favor ofExceptT
, and thatExceptT
is only more general so the transition should be trivial if you decide to switch.