如何让Reader和ReaderT协同工作

时间:2015-02-08 22:38:09

标签: haskell monads

我使用ReaderT Monad转换器通过执行IO的几个函数从我的main函数传播我的配置数据。需要数据的最终功能不执行任何IO。我有这个有效的解决方案:

import Control.Monad.Reader

type Configuration = String

funNoIO :: Reader Configuration String
funNoIO = do
    config <- ask
    return $ config ++ "!"

funIO :: ReaderT Configuration IO String
funIO = do
    config <- ask
    return $ runReader funNoIO config

main :: IO ()
main = do
    c <- runReaderT funIO "configuration"
    print c

但它迫使我在funIO函数中检索我不需要它的配置。

我这样修改了它:

funIO' :: ReaderT Configuration IO String
funIO' = do
    v <- funNoIO
    return v

但它没有编译,我收到此错误:

Couldn't match type ‘ReaderT Configuration Identity String’
              with ‘Identity (ReaderT Configuration IO String)’
Expected type: Identity (ReaderT Configuration IO String)
  Actual type: Reader Configuration String
In the first argument of ‘runIdentity’, namely ‘funNoIO’
In a stmt of a 'do' block: v <- runIdentity funNoIO

是否可以将我的配置数据传播到纯函数而无需在中间IO函数中检索它?

修改

我参与了我的功能,但我仍然无法在funIO'功能中执行IO操作。例如:

getMessage :: IO String
getMessage = do
    return "message"

funIO' :: MonadIO m => ReaderT Configuration m String
funIO' = do
    m <- getMessage
    v <- funNoIO
    return $ v ++ m

给我以下错误:

Couldn't match type ‘IO’ with ‘ReaderT Configuration m’
Expected type: ReaderT Configuration m String
Actual type: IO String

编辑2

我知道了,我只需要使用liftIO

getMessage :: IO String
getMessage = do
    return "message"

funIO' :: MonadIO m => ReaderT Configuration m String
funIO' = do
    m <- liftIO getMessage
    v <- funNoIO
    return $ v ++ m

2 个答案:

答案 0 :(得分:3)

另一种方法是使用reader的{​​{1}}方法和MonadReader

runReader

funIO = reader $ runReader funNoIO 从纯reader . runReader monad转换为更一般的Reader实例。

答案 1 :(得分:2)

您可以更改要在monad类型中参数化的funNoIOfunIO的类型,因为它们未被使用:

funNoIO :: Monad m => ReaderT Configuration m String
funIO' :: Monad m => ReaderT Configuration m String

修复编译器错误,然后您可以将main更改为:

main = do
    c <- runReaderT funIO' "configuration"
    print c