2012-03-14 12 views
7

に外モナドの更新:私は失敗し、いくつかのログをして、計算のためのモナドを持っている唯一のモナド変換

f2 :: Writer [String] b 

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

私はいくつかのログを失敗したがいません機能を持っています

f2のログを使ってf1のライターモナドを更新し、f2計算の出力をキャプチャする最良の方法は何ですか?現時点では私はこれをやっている:私は作家を中心に切り替え、どちらかのモナドは、問題を解決することはできません、別の計算で、内部モナドを更新するためにリフトを使用しています

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

+0

ありがとうdanrとホタルブクロ:コメントで

は、ホタルブクロはこの設定で機能を包むのバージョンを与えました。私はwrapメソッドを使用することを選択しました。私はf2の型を変更することができますが、その関数は他のコンテキストで表示されるので、特定の呼び出し関数の必要性を参照せずにその型を記述したいと思います。 – mskel

答えて

4

あなたがf2を定義した場合、最も簡単な可能なアプローチは、それがthusly定義されていますf2をリファクタリングすることがあります

Writer w bWriterT w Identity bのように定義されているので、それほど難しいことではありません
f2 :: Monad m => WriterT [String] m b 

、およびIdentityモナドのdoesnあなたに何かを与えません。

次に、f1 >> f2を実行するだけで連鎖させることができます。

あなたがf2を再定義することができない場合は、常に適切な署名で独自に定義することができます:

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

そして、あなたがラップするf2の束をしている場合は、常にラップする関数を定義することができあなた

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

ですから、ホタルブクロの答えをフォローアップとしてf1 >> wrap f2a >> wrap f2b >> wrap f2c ...

4

を行うことができ、あなたが代わりにrefができるため、それら任意のMonadWriterの俳優f2

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

は、その定義を変更することはできないであなたは ホタルブクロが行うのと同様に、それをラップすることができますする必要があります

MonadWriterから [String]引数がこのGHCプラグマを必要
f2' :: MonadWriter [String] m => m a 
f2' = do let (a,w) = runWriter f2 
     tell w 
     return a 

{-# LANGUAGE FlexibleContexts #-} 

いつものように、プラグマar eモジュールの上に置きます。あなたの応答のための

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

ラッパーは 'wrap :: MonadWriter w m => Writer w b - > m bになります。 wrap = uncurry(<<)。 (return *** tell)。 runWriter where(<<) = flip (>>) ' – rampion

+0

@rampion:Nice!私はポイントフリーのスタイルに感謝することができます;) – danr

+0

まあ、私は相互賞賛の社会に参加し、私はMonadWriter typeclassに一般化を感謝することができます:) – rampion

関連する問題