2011-11-16 65 views
6

我有以下樣板,我經常做,並希望消除。它看起來是這樣的:Haskell ReaderT環境IO樣板

type Configured = ReaderT Config 

doSomething :: Configured IO Data 
doSomething = do 
    getMeta <- asks getMetaData 
    meta <- liftIO getMeta 

我想,以減少對這樣的事情:

doSomething = do 
    meta <- find getMetaData 

不幸的是,我還沒有完全包裹我的腦海裏圍繞單子變壓器呢。什麼是find的類型?是(Config -> IO Result) -> Result?我如何編寫它?

任何提示/解釋,以幫助我grok單子變壓器非常讚賞。

謝謝!

+3

我沒有時間,現在來解釋這一點,但這裏的東西:find'的'類型是'(配置 - > IO結果) - >配置IO Result'在你的榜樣,更普遍'單子M = >(r - > ma) - > ReaderT rma'。您可以將其定義爲'find = ask> => lift'。 – Miikka

回答

11

這可以以相當機械的方式完成。讓我們先從你的原始代碼:

doSomething = do 
    getMeta <- asks getMetaData 
    meta <- liftIO getMeta 
    ... 

使用the third monad law,我們被允許移動,我們要提取到自己的DO-塊的部分:

doSomething = do 
    meta <- do getMeta <- asks getMetaData 
       liftIO getMeta 
    ... 

接下來,我們可以只提取該子表達式,並給它一個名字:

findMetaData = do getMeta <- asks getMetaData 
        liftIO getMeta 

doSomething = do 
    meta <- findMetaData 
    ... 

最後,讓我們用一個參數來代替的getMetaData明確提到概括它:

find something = do x <- asks something 
        liftIO x 

doSomething = do 
    meta <- find getMetaData 
    ... 

現在,我們可以在ghci中加載它,並要求它來推斷類型我們:

*Main> :t find 
find :: (MonadReader r m, MonadIO m) => (r -> IO b) -> m b 

或者,我們可能希望把它清理乾淨一點,取走假命名x

find something = ask >>= liftIO . something 

要做到這一點,我用the definition of asksthe desugaring rules for do-notation

+2

更進一步的(如Miikka所指出的)讓你「find = ask> => liftIO」。謝謝!現在有道理。 – So8res