2012-03-14 2 views
7

I 실패 일부 로깅 수행 할 수있는 연산에 대한 모나드 가지고만 모나드 변압기 외측 모나드 업데이트

f1 :: WriterT [String] (Either String) a 

I 실패하지만, 몇몇 기록하지 않을 것이다 함수 가지고

f2 :: Writer [String] b 

f2의 로그를 사용하여 f1의 작성자 모나드를 업데이트하고 f2 계산의 출력을 캡처하는 가장 좋은 방법은 무엇입니까? 순간 나는이 일을 해요 : 나는 그래서 작가 중심으로 전환하고 하나의 모나드 문제가 해결되지 않습니다, 다른 계산과 내부 모나드를 업데이트 리프트를 사용하고

f2result <- (\(r,l) -> do {tell l; return r}) (runWriter f2) 

.

+0

감사 danr 및 rampion : 코멘트에

는 rampion는이 설정에서 기능을 포장의 버전을했다. wrap 메서드를 사용하기로했습니다. f2의 형식을 변경할 수는 있지만 그 함수는 다른 컨텍스트에 나타나므로 특정 호출 함수의 필요성에 대한 참조없이 형식을 작성하고 싶습니다. – mskel

답변

4

당신은 f2, 가장 쉬운 가능한 방법은 f2를 리팩토링 할 수 있습니다를 정의한 경우 그래서 thusly 히 정의되어 : Writer w bWriterT w Identity b로 정의되어 있기 때문에, 너무 열심히하지 않아야

f2 :: Monad m => WriterT [String] m b 

하고 Identity 모나드 아무튼 아무것도주지 마라.

그런 다음 f1 >> f2을 수행하면 체인을 연결할 수 있습니다.

f2' :: Monad m => WriterT [String] m b 
f2' = WriterT . return $ runWriter f2 

을 그리고 당신은 포장 f2의 무리를 한 경우, 당신은 항상 포장하는 함수를 정의 할 수 있습니다 :

당신이 f2를 재정의 할 수없는 경우, 당신은 항상 적절한 서명으로 자신을 정의 할 수 있습니다 그 A가 rampion의 대답에 후속, 대신 심판 수 있듯이 당신이

그래서
wrap :: Monad m => Writer w b -> WriterT w m b 
wrap = WriterT . return . runWriter 

당신이 f1 >> wrap f2a >> wrap f2b >> wrap f2c ...

4

을 수행 할 수 있습니다에 대한 어떤 MonadWriter에 배우 f2 :

f2 :: MonadWriter [String] m => m a 

이 정의를 변경하는 것이 가능하지 않을 당신이 rampion가하는 유사로 포장 할 수 있어야 :

MonadWriter[String] 인수가이 GHC 프라그를 필요로
f2' :: MonadWriter [String] m => m a 
f2' = do let (a,w) = runWriter f2 
     tell w 
     return a 

:

{-# LANGUAGE FlexibleContexts #-} 

항상 그렇듯이 pragma ar e 모듈 상단에 놓습니다. 당신의 응답을

wrap :: MonadWriter w m => Writer w b -> m b 
wrap = uncurry (<<) . (return *** tell) . runWriter 
    where (<<) = flip (>>) 
+1

래퍼가'wrap :: MonadWriter w m => 라이터 w b -> m b가된다; wrap = uncurry (<<). (return *** tell). runWriter where (<<) = flip (>>)' – rampion

+0

@rampion : 니스!나는 포인트 프리 스타일을 고맙게 생각할 수있다.) – danr

+0

음, 상호 존중 사회에 참여하게하고, MonadWriter typeclass에 대한 일반화에 감사 할 수 있다고 말한다. :) – rampion