我使用ReaderT Monad转换器通过执行IO的几个函数从我的主函数传播配置数据。将需要数据的最终功能不会执行任何IO。我有这个工作液:如何让Reader和ReaderT一起工作
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
EDIT 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
是的。让编译器推断每个函数的最一般类型。如果你这样做,'funIO''编译。或者甚至是'funNoIO :: Monad m => ReaderT Configuration m String'都可以工作 - 因为你从不操纵内部monad,所以它可以是任何东西。那么'funIO''的一个合理类型是'MonadIO m => ReaderT Configuration m String' - MonadIO约束将来自定义内部对'liftIO'的任何使用。 – user2407038 2015-02-08 22:56:50
你可以保持funNoIO为简单的Reader,如果你将它与'IO'相关的东西混合使用'mmorph'方法https://hackage.haskell.org/package/mmorph-1.0.4,写'提升概括funNoIO'。文档中的示例使用与您的状态完全平行的“State/StateT”示例。 “提升机”有许多其他应用。 – Michael 2015-02-09 01:14:45