3

異なる ReaderT 環境を組み合わせることができれば便利だと思われます。

たとえば、一般的なロギング機能は次のようになります。

logit :: Text -> ReaderT Bool  IO ()
logit str = do debugflag <- ask
               liftIO $ if debugflag then putStrLn ("debug: " ++ str) else return ()

これは、再利用可能な優れたコンポーネントのように見えます。では、この定義を別の ReaderT 環境と統合して、両方を使用できるようにするにはどうすればよいでしょうか?

たとえば、次の ReaderT インスタンスと組み合わせたいとします。

foo :: ReaderT Text IO ()
foo = ...

同じ関数でfooとの両方を使用できるようにします。logit

4

1 に答える 1

1

それらを積み重ねたモナドに重ねたいと思うでしょうが、両方ともそれIOがまさにラップされたモナドであると宣言しているので、それらを一緒に積み重ねることはできません。幸いなことに、コードはすでにこの制限を解除するのに十分一般的です。関数の最も一般的なタイプは、MonadIO具体的に使用する代わりに を使用しIOます。タイプを次のように変更すると、

 logit :: MonadIO m => Text -> ReaderT Bool m ()
 foo   :: MonadIO m =>         ReaderT Text m ()

次に、liftIO呼び出しはIOアクションをスタック全体からIO一番下のモナドに持ち上げます。

明確にするために、作成した型を使用する必要はありません。liftIO同じ型は だけで満たされますliftが、IOは (自明に) のインスタンスであるためMonadIO、(過度に) 特殊化された型もチェッカーに合格します。

于 2013-01-30T16:58:45.210 に答える