如何让 Reader 和 ReaderT 协同工作
How to get Reader and ReaderT to work together
我正在使用 ReaderT Monad 转换器通过几个执行 IO 的函数从我的主要函数传播我的配置数据。需要数据的最终函数不执行任何 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
您可以更改 funNoIO
和 funIO
的类型以在 monad 类型上进行参数化,因为它们未被使用:
funNoIO :: Monad m => ReaderT Configuration m String
funIO' :: Monad m => ReaderT Configuration m String
修复编译错误,那么可以将main
改成:
main = do
c <- runReaderT funIO' "configuration"
print c
另一种方法是将MonadReader
的reader
方法与runReader
一起使用:
funIO = reader $ runReader funNoIO
reader . runReader
从纯 Reader
monad 转换为更通用的 MonadReader
实例。
我正在使用 ReaderT Monad 转换器通过几个执行 IO 的函数从我的主要函数传播我的配置数据。需要数据的最终函数不执行任何 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
您可以更改 funNoIO
和 funIO
的类型以在 monad 类型上进行参数化,因为它们未被使用:
funNoIO :: Monad m => ReaderT Configuration m String
funIO' :: Monad m => ReaderT Configuration m String
修复编译错误,那么可以将main
改成:
main = do
c <- runReaderT funIO' "configuration"
print c
另一种方法是将MonadReader
的reader
方法与runReader
一起使用:
funIO = reader $ runReader funNoIO
reader . runReader
从纯 Reader
monad 转换为更通用的 MonadReader
实例。