2012-04-04 38 views
5

creo que me falta algún conocimiento básico de los transformadores mónada, porque me encontré escribiendo este código:Ascensor transformador mónada ErrorT

import Control.Monad.Identity 
import Control.Monad.Error 

liftError :: Either String Int -> ErrorT String Identity Int 
liftError x = do case x of 
        Right val -> return val 
        Left err -> throwError err 

gateway :: Bool -> ErrorT String Identity Int 
gateway = liftError . inner 

inner :: Bool -> Either String Int 
inner True = return 5 
inner False = throwError "test" 

Aunque esto funciona, creo que esto se podría hacer más esmeradamente. En particular, estoy buscando un reemplazo de liftError, que creo que no debería tener que definir por mí mismo.

¿Cuál sería la forma más directa de hacer que gateway y inner trabajen juntos sin cambiar su tipo?

Respuesta

6

Si solo cambia los tipos un poco, no tiene que levantar nada en absoluto.

{-# LANGUAGE FlexibleContexts #-} 

gateway :: Bool -> ErrorT String Identity Int 
gateway = inner 

inner :: MonadError String m => Bool -> m Int 
inner True = return 5 
inner False = throwError "test" 

MonadError tiene instancias, tanto para ErrorT y Either, por lo que de esta manera se puede utilizar tanto como inner.

+0

Bien, para ser más específico, ¿tengo que escribir una función de elevación manual si quiero dejar los tipos como están? Esto es solo para mi comprensión. Por desgracia, no puedo votar más hoy:/Recibirá la votación mañana :) –

+1

Sin cambiar los tipos, puede usar 'ErrorT. return' en lugar de su función 'liftError'. También puede usar la versión más general internamente y solo exponer una copia de 'inner' con el tipo restringido. – hammar

+0

Ese 'ErrorT. return' era exactamente lo que estaba buscando. Como mencioné, esto no tiene nada que ver con ningún código real, solo quiero entender el concepto de transformadores de mónada :) –

Cuestiones relacionadas