2011-11-16 12 views
6

Tengo la siguiente plantilla repetitiva que hago bastante a menudo, y me gustaría eliminar. Se ve algo como esto:Haskell ReaderT Env IO estándar

type Configured = ReaderT Config 

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

me gustaría que para reducir a algo como esto:

doSomething = do 
    meta <- find getMetaData 

Por desgracia, no he envuelto completamente alrededor de mi mente transformadores monad todavía. ¿Cuál es el tipo de find? ¿Es (Config -> IO Result) -> Result? ¿Cómo lo escribo?

Cualquier consejo/explicación para ayudarme a comprender los transformadores de mónada son muy apreciados.

Gracias!

+3

No tengo tiempo ahora para explicar esto, pero hay algo: el tipo de 'encontrar' es' (Config -> Resultado IO) -> Resultado IO configurado 'en su ejemplo y más generalmente 'Monad m = > (r -> ma) -> ReaderT rma'. Puede definirlo como 'find = asks> => lift'. – Miikka

Respuesta

11

Esto se puede hacer de una manera bastante mecánica. Vamos a empezar con el código original:

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

Usando the third monad law, se nos permite mover la parte que queremos extraer en un do-bloque de su propia:

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

A continuación, sólo podemos extraer que subexpresión y darle un nombre:

findMetaData = do getMeta <- asks getMetaData 
        liftIO getMeta 

doSomething = do 
    meta <- findMetaData 
    ... 

por último, vamos a generalizar sustituyendo la referencia explícita a getMetaData con un parámetro:

find something = do x <- asks something 
        liftIO x 

doSomething = do 
    meta <- find getMetaData 
    ... 

Ahora, podemos cargarlo en GHCi y pedirle que inferir el tipo para nosotros:

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

Opcionalmente, se puede querer limpiarlo un poco y extraer al maniquí nombrar x:

find something = ask >>= liftIO . something 

Para hacer esto, solía the definition of asks y the desugaring rules for do-notation.

+2

Y un paso más allá (según lo observado por Miikka) le da "find = asks> => liftIO". ¡Gracias! Tiene sentido ahora. – So8res