10

私は標準のHaskellライブラリに基づいてモナド変換子を学ぼうとしています(mtl?変換子?Haskellプラットフォームのダウンロードに付属しているものがどれかわからない-7.4.1)。

私が気付いたのは、各モナド変換子の定義に共通する構造です。

  1. ベースタイプ(「ベース」)

    • モナドインスタンス
  2. 変圧器タイプ(「BaseT」)

    • モナドインスタンス

    • MonadTransインスタンス

    • MonadIOインスタンス

  3. トランスフォーマークラス('MonadBase')

    • いくつかの操作

    • 他の'BaseTのインスタンス

したがって、たとえば、Writerモナドの場合、次のようになります。

  • Monadインスタンスを持つWriterデータ型/ニュータイプ/タイプ
  • WriterTデータ型/ニュータイプ/タイプ、Monad、MonadTrans、およびMonadIOインスタンス
  • MonadWriterクラス、およびStateT、ReaderT、IdentityT、..のこのクラスのインスタンス

これはモナド変換子の構成方法ですか?何か足りないものがありますか/間違った詳細がありますか?

この質問の動機は、次のことを理解することです。

  1. 「BaseT」と対応する「MonadBase」および「Base」の間の関係と違いは何ですか
  2. 3つすべてが必要かどうか
  3. MonadTransがどのように関連し、その目的は何ですか
4

1 に答える 1

4

mtlパッケージはモナド変換子を実装していません。少なくとも WriterT は から再エクスポートさtransformersれたばかりです。

transformersパッケージWriterTは、モナドトランスフォーマー自体である を実装します。Writer単なるエイリアスです:

type Writer w = WriterT w Identity

一部のライブラリはWriter個別に実装できますが、とにかくそれはWriterT. (Identityは自明なモナドであり、追加の動作はありません。)

MonadTrans基礎となるモナドを変換されたものにラップすることができます。これがなくても問題はありませんが、手動でラッピングを行う必要があります (方法については、MonadTransインスタンス定義を参照WriterTしてください)。本当に必要な唯一の使用例MonadTrans- 変圧器の実際のタイプがわからない場合。

MonadWriterで宣言された型クラスmtlです。そのメソッド ( writerpasstellおよびlisten) は function for と同じですWriterTWriterTスタック内のトランスフォーマーの正確なタイプ (さらには数も!) がわからない場合でも、トランスフォーマーのスタックを介して(自動的に!) 計算をラップできます。

したがって、WriterT「必須」の唯一のタイプです。

他のモナドトランスフォーマーについても同じです:BaseTはトランスフォーマーでBaseあり、基礎となるモナドを持たないモナドでMonadBaseあり、型クラスBaseT(トランスフォーマースタックのどこかにあるすべてのモナドのクラス) です。

追加した:

RWHの本で素晴らしい説明を見つけることができます

以下に基本的な例を示します。

import Control.Monad.Trans
import Control.Monad.Trans.Writer
import Control.Monad.Trans.Reader hiding (ask)

-- `ask` from transformers
-- ask :: Monad m => ReaderT r m r
import qualified Control.Monad.Trans.Reader as TransReader (ask)

-- `ask` from mtl
-- ask :: MonadReader r m => m r
import qualified Control.Monad.Reader as MtlReader (ask)

-- Our monad transformer stack:
-- It supports reading Int and writing String
type M m a = WriterT String (ReaderT Int m) a

-- Run our monad
runM :: Monad m => Int -> M m a -> m (a, String)
runM i action = runReaderT (runWriterT action) i

test :: Monad m => M m Int
test = do
  tell "hello"
  -- v <- TransReader.ask     -- (I) will not compile
  v1 <- lift TransReader.ask  -- (II) ok
  v2 <- MtlReader.ask         -- (III) ok
  return (v1 + v2)

main :: IO ()
main = runM 123 test >>= print

(I)コンパイラによって拒否されることに注意してください(エラーメッセージを確認してみてください!)。しかし、 (「明示的なリフティング」)(II)のおかげでコンパイルされます。MonadTransのおかげでMonadReader(III)すぐに使用できます (「暗黙のリフティング」)。どのように機能するかについては、RWH の本をお読みください。

(この例ではask、2 つの異なるモジュールからインポートするため、修飾されたインポートが必要です。通常は、一度に 1 つのみを使用します。)

また、特に質問するつもりはありませんでしたWriter

よくわかりません... ReaderStateおよび他の人が同じスキーマを使用しています。に置き換えるWriterState、 の説明が表示されStateます。

于 2012-11-28T17:40:12.003 に答える