2017-01-03 4 views
1

Haskellのエラーモナドと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の2番目の引数として何を入れるべきかわかりません。私はそれが次のタイプシグネチャであるべきだと思う:Either String Direction -> AskMonad Directionしかし、再実行する必要がある計算にはどうすればアクセスできますか(この場合はaskSomething)。

+1

あなたはこの(討論された)[エラー処理in haskell](https://www.schoolofhaskell.com/user/commercial/content/exceptions-best-practices)に興味があるかもしれません。 – mb21

答えて

2

コードは、ErrorT String結果で表されていない例外をキャッチしようとしているようです。私の考えは、runErrorTの結果がLeftの値(「予想される」例外)の場合、実際に再試行したいと考えているということです。その場合には、このretryForeverようなものが働く可能性があります

direction <- retryForever askSomething 

P.S.:のように使用することができ

retryForever :: AskMonad a -> IO a 
retryForever action = 
    runErrorT action >>= either (\ex -> putStrLn ex >> retryForever action) return 

私はErrorTの代わりにExceptTが推奨されており、ExceptTはより一般的なものだと考えています。

関連する問題