抛出错误后重新运行计算
Rerun computation after throwing error
我想在 Haskell 中组合 Error Monad 和 IO Monad。这是我的代码的摘录:
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...
我想实现以下行为:
- 如果
askSomething
成功,得到Direction
.
- 如果
askSomething
失败,show
错误并再次 运行 askSomething
。
但是,我不知道要将什么作为 catchError
的第二个参数来实现此行为。我认为它应该是以下类型签名:Either String Direction -> AskMonad Direction
,但是我如何访问需要重新计算的计算运行(在这种情况下为askSomething
)。
您现在拥有的代码似乎会尝试捕获 ErrorT String
结果中未表示的异常。我的想法是,如果 runErrorT
导致 Left
值("expected" 异常),您实际上希望重试。在那种情况下,像这样的 retryForever
可能会起作用:
retryForever :: AskMonad a -> IO a
retryForever action =
runErrorT action >>= either (\ex -> putStrLn ex >> retryForever action) return
可以这样使用:
direction <- retryForever askSomething
P.S。我相信 ErrorT
已被弃用,取而代之的是 ExceptT
,并且 ExceptT
只是更通用,因此如果您决定切换,过渡应该是微不足道的。
我想在 Haskell 中组合 Error Monad 和 IO Monad。这是我的代码的摘录:
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...
我想实现以下行为:
- 如果
askSomething
成功,得到Direction
. - 如果
askSomething
失败,show
错误并再次 运行askSomething
。
但是,我不知道要将什么作为 catchError
的第二个参数来实现此行为。我认为它应该是以下类型签名:Either String Direction -> AskMonad Direction
,但是我如何访问需要重新计算的计算运行(在这种情况下为askSomething
)。
您现在拥有的代码似乎会尝试捕获 ErrorT String
结果中未表示的异常。我的想法是,如果 runErrorT
导致 Left
值("expected" 异常),您实际上希望重试。在那种情况下,像这样的 retryForever
可能会起作用:
retryForever :: AskMonad a -> IO a
retryForever action =
runErrorT action >>= either (\ex -> putStrLn ex >> retryForever action) return
可以这样使用:
direction <- retryForever askSomething
P.S。我相信 ErrorT
已被弃用,取而代之的是 ExceptT
,并且 ExceptT
只是更通用,因此如果您决定切换,过渡应该是微不足道的。