我使用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