2015-02-08 109 views
3

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

是的。讓編譯器推斷每個函數的最一般類型。如果你這樣做,'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

+1

你可以保持funNoIO爲簡單的Reader,如果你將它與'IO'相關的東西混合使用'mmorph'方法https://hackage.haskell.org/package/mmorph-1.0.4,寫'提升概括funNoIO'。文檔中的示例使用與您的狀態完全平行的「State/StateT」示例。 「提升機」有許多其他應用。 – Michael 2015-02-09 01:14:45

回答

2

你可以將funNoIOfunIO的類型更改爲通過monad類型si進行參數化NCE他們不習慣:

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

修復編譯器錯誤,那麼你可以改變main到:

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

你也可以讓他們的類型簽名'MonadReader Configuration m => m String' – Mokosha 2015-02-09 01:30:22

3

另一種方式是與runReader一起使用的MonadReaderreader方法:

funIO = reader $ runReader funNoIO 

reader . runReader將純粹的Reader monad轉換爲更屬的MonadReader實例。