私はモナド変換子を研究していて、sを回避する方法についてこのSOの投稿を読みましたlift
。
私の考えでは、それMonadIO
はIO
埋め込むことができるモナドであり、埋め込むことができるMonadWriter w
モナドWriterT w
です。そこで、以下のコードを記述しました(ゼロになるまで数値を読み取り、累積し、記録します)。ここでlift
は、explicitを使用した作業バージョンがコメントに含まれています。しかし、GHCは文句を言います。私は何が間違っているのですか?
{-# LANGUAGE FlexibleContexts #-}
import Control.Monad.IO.Class
import Control.Monad.Writer.Class (MonadWriter)
import Control.Monad.Trans.Reader
import Control.Monad.Trans.Writer
-- f :: ReaderT Int (WriterT [String] IO) Int
-- m1 = ReaderT, m2 = WriterT
f :: (MonadWriter [String] m1, MonadIO m2) => m1 (m2 (IO Int))
f = do
s <- liftIO getLine
tell ["Input: " ++ s] -- lift $ tell ["Input: " ++ s]
let i = read s :: Int
if i == 0
then ask
else local (+i) f
main = do
rst <- runWriterT $ runReaderT f 0
print rst
私の考えでは、MonadIOはIOを埋め込むことができるモナドであり、MonadWriterwはWriterTwを埋め込むことができるモナドです。
それは完全には正しくありません。MonadIO
sはliftIO
、をMonadWriter
使用でき、はを使用できますtell
。あなたが使用したい場合はそのため、liftIO
、tell
、ask
とlocal
持ち上げずに同じコンテキスト/モナドでは、単一使用モナドは、それらのすべてのインスタンスでなければなりません。
f :: ( MonadWriter [String] m -- monad supports tell :: [String] -> m ()
, MonadReader Int m -- monad supports ask :: m Int
, MonadIO m -- monad supports liftIO :: IO a -> m a
) => m Int -- only a single m
を使用することはできませんがtransformer
、mtl
自動リフトを取得するために使用できることに注意してください。したがって、インポートも変更されます。
import Control.Monad.Reader (runReaderT, MonadReader)
import Control.Monad.Writer (runWriterT, MonadWriter)
import Control.Monad.IO.Class (liftIO, MonadIO)
アクションが自動的に解除されることMonadIO
はないため、のインポートは変更されませんIO
。
ところで、あなたの使用runWriterT
とはrunReaderT
、これが使用されますので、すでに、すべてのあいまいさに変圧器スタックを削除します
ReaderT Int (WriterT [String] IO Int)
この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。
侵害の場合は、連絡してください[email protected]
コメントを追加