2017-01-03 5 views
1

하스켈에서 오류 모나드와 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).

+1

[haskell의 오류 처리] (https://www.schoolofhaskell.com/user/commercial/content/exceptions-best-practices)에 대한이 (관심이있는) 게시물에 관심이있을 수 있습니다. – mb21

답변

2

코드는 ErrorT String 결과에 표시되지 않은 예외를 잡으려고하는 것처럼 보입니다. 제 생각에 runErrorT 결과가 Left 값 ("예상"예외) 일 경우 실제로 재 시도하려고합니다. 이 경우,이 retryForever과 같이 작동 할 수 :

direction <- retryForever askSomething 

추신 :처럼 사용할 수

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

나는 ErrorT이 (가) ExceptT에 찬성하여 더 이상 사용되지 않으며, ExceptT이 더 일반적인 것일 뿐이므로 전환을 결정할 때 전환이 간단해야한다고 생각합니다.