2014-04-17 3 views
3

일부 상태 정보 (로깅 등)를 추적하기 위해 StateT 모나드 변환기를 사용하는 코드를 작성 중입니다.실패 할 때 정보를 보존하는 방법?

내가 StateT에 전달하고있어 모나드는 매우 간단합니다 :

data CheckerError a = Bad {errorMessage :: Log} | Good a 
    deriving (Eq, Show) 


instance Monad CheckerError where 
    return x = Good x 

    fail msg = Bad msg 

    (Bad msg) >>= f = Bad msg 
    (Good x) >>= f = f x 

type CheckerMonad a = StateT CheckerState CheckerError a 

그것은 단지 LeftRight 변형입니다.

무슨 문제가 있습니까? fail의 정의입니다. 필자의 계산에서 나는이 모나드 내부에 많은 정보를 생성하고 실패 할 때에도이 정보를 유지하고자한다. 현재 내가 할 수있는 일은 모든 것을 으로 변환하고 에 인수로 전달 된 String으로 Bad 인스턴스를 생성하는 것입니다. 내가 지금까지 시도

fail msg = do 
    info <- getInfoOutOfTheComputation 
    return $ Bad info 

그러나 모든이 다른 모나드를 혼합 것 아마 때문에, 오류를 입력 제공 : 내가하고 싶은 무엇

은 같은 것입니다.

String으로 변환하지 않고도 필요한 정보를 보존하기 위해 fail을 구현할 수 있습니까?

나는 최선의 하스켈이 show + read을 사용하여 문자열로 모든 정보를 fail으로 전달한다고 믿을 수 없다.

+0

짧은 대답 : 그것은 '실패'가 아니라, 당연히 작동하지 않습니다. – Carl

+0

@Carl 그럼 어떻게해야하는지 보여주세요. 내가 원하는 것 : 1) 나쁜 일이 발생할 때 계산을 "중지"하는 방법 2) 그 시점까지 생성 된 상태 정보를 보존합니다. 필자가 보았던 모든 예제는'fail'을 1 회 사용하고 2 번을 달성하지 못한다. 현재 나와있는 유일한 방법은'prettyFail = do state <- get; 모든 상태 정보에서'Show $'상태를''show''및''Read ''를 구현하지 못했습니다. – Bakuriu

+2

'fail'은 do 표기법의 패턴 일치 실패를 지원하기위한 임시 방편 조치로만 사용됩니다. –

답변

7

CheckerError 모나드는 Either 모나드와 매우 유사합니다. 나는 내 대답에 Either 모나드 (그리고 모나드 변압기 대응 물 ErrorT)를 사용할 것이다.

모나드 전환기에는 미묘한 차이가 있습니다. "내부"모나드의 효과는 "외부"레이어로 인한 영향보다 우선합니다. CheckerMonad 이러한 두 대체 정의를 고려

import Control.Monad.State 
import Control.Monad.Error 

type CheckerState = Int  -- dummy definitions for convenience 
type CheckerError = String 

type CheckerMonad a = StateT CheckerState (Either String) a 

type CheckerMonad' a = ErrorT String (State CheckerState) a 

CheckerMonad에서 Either 이너 모나드이며, 이는 모든 상태를 초기화하는 장애를 의미한다. 이 실행 함수의 유형을 확인하십시오.

runCM :: CheckerMonad a -> CheckerState -> Either CheckerError (a,CheckerState) 
runCM m s = runStateT m s 

해당 지점까지 상태가 실패하거나 결과가 반환됩니다.

CheckerMonad'에서 State은 내부 모나드입니다. 이 상태는 심지어 고장시에 보존한다 의미 그 시점까지의 상태를 포함하는 한 쌍의 리턴

runCM' :: CheckerMonad' a -> CheckerState -> (Either CheckerError a,CheckerState) 
runCM' m s = runState (runErrorT m) s 

, 및 오류 또는 결과 중 하나.

모나드 변환기를 올바르게 주문하는 방법에 대한 직관을 개발하는 데 약간의 연습이 필요합니다. Type juggling 섹션의 차트는 this Wikibook page입니다.

fail 또한 언어에서 사마귀로 간주되기 때문에 직접 사용하지 않는 것이 좋습니다.대신 오류 변환기가 제공하는 오류를 던지기위한 특수 함수를 사용하십시오. ErrorT 또는 MonadError의 다른 인스턴스로 작업 할 때는 throwError을 사용하십시오.

sillycomp :: CheckerMonad' Bool 
sillycomp = do 
    modify (+1) 
    s <- get 
    if s == 3 
     then throwError "boo" 
     else return True 

*Main> runCM' sillycomp 2 
Loading package transformers-0.3.0.0 ... linking ... done. 
Loading package mtl-2.1.2 ... linking ... done. 
(Left "boo",3) 

*Main> runCM' sillycomp 3 
(Right True,4) 

ErrorTEither 달리 오류 유형에 Error 제약 조건을 필요로하기 때문에 사용하는 것이 때로는 성가신입니다. Error typeclass를 사용하면 두 개의 오류 생성자 noMsgstrMsg을 정의해야합니다.이 유형은 사용자의 유형에 적합하거나 그렇지 않을 수 있습니다.

대신 패키지의 EitherT을 사용할 수 있습니다. 따라서 어떤 유형의 오류라도 사용할 수 있습니다. EitherT으로 작업 할 때는 left 함수를 사용하여 오류를 던집니다.

관련 문제