2011-11-16 11 views
6

Ho la seguente etichetta che faccio abbastanza spesso e vorrei eliminare. Sembra qualcosa di simile:Haskell ReaderT Env IO boilerplate

type Configured = ReaderT Config 

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

mi piacerebbe ridurre tale a qualcosa di simile:

doSomething = do 
    meta <- find getMetaData 

Purtroppo, non ho completamente avvolto la mia mente intorno trasformatori monade ancora. Qual è il tipo di find? È (Config -> IO Result) -> Result? Come lo scrivo?

Eventuali suggerimenti/spiegazioni per aiutarmi a convincere i trasformatori monad sono molto apprezzati.

Grazie!

+3

Non ho tempo per spiegare questo, ma ecco qualcosa: il tipo di 'find' è' (Config -> Risultato IO) -> Risultato IO configurato 'nell'esempio e più in generale 'Monad m = > (r -> ma) -> ReaderT rma'. Puoi definirlo come 'find = asks> => lift'. – Miikka

risposta

11

Questo può essere fatto in modo abbastanza meccanico. Cominciamo con il tuo codice originale:

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

Utilizzando the third monad law, c'è permesso di muovere la parte che vogliamo estrarre in un fai-da blocco a sé stante:

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

Avanti, possiamo semplicemente estrarre che sottoespressione e dargli un nome:

findMetaData = do getMeta <- asks getMetaData 
        liftIO getMeta 

doSomething = do 
    meta <- findMetaData 
    ... 

Infine, cerchiamo di generalizzare sostituendo il riferimento esplicito alla getMetaData con un parametro:

find something = do x <- asks something 
        liftIO x 

doSomething = do 
    meta <- find getMetaData 
    ... 

Ora, siamo in grado di caricarlo in GHCi e chiedergli di dedurre il tipo per noi:

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

Opzionalmente, si potrebbe desiderare di ripulirlo un po 'e rimuovere il manichino citarne x:

find something = ask >>= liftIO . something 

Per fare questo, ho usato the definition of asks e the desugaring rules for do-notation.

+2

E un passo avanti (come notato da Miikka) ti dà "find = asks> => liftIO". Grazie! Ha senso ora. – So8res