2011-12-22 18 views
5

Tengo el siguiente transformador de mónada para tratar los errores en Haskell.Mónadas Haskell y un fallo que no requiere una cadena

instance (Monad m, Error e) => Monad (EitherT e m) where 
    return = EitherT . return . return 
    m >>= k = EitherT $ do 
      a <- runEitherT m 
      case a of 
       Left l -> return (Left l) 
       Right r -> runEitherT (k r) 
    fail = EitherT . return . Left . strMsg 

funciona bastante bien, ya que puedo crear una instancia Error con una clase personalizada y tener un medio bastante flexibles por lo que para controlar los errores.

fail es un poco tonto, sin embargo, porque es el tipo String -> EitherT e m, y la restricción String puede ser una forma molesta de crear errores. Termino con una gran cantidad de:

instance Error BazError where 
    strMsg "foo" = FooError -- oh look we have no error context 
    strMsg "bar" = BarError -- isn't that nice 

Lo que me gustaría hacer es crear una nueva función, como fail, que es de tipo a -> e para que pueda eliminar la restricción (Error e). fail es especialmente conveniente cuando la pila mónada se hace grande, como cuando termino con

EitherT BazError (StateT [BazWarning] IO) Foo 

¿Hay una manera de crear una función que tiene el mismo comportamiento que fail con un tipo menos restrictivo? ¿O está implementado el fail usando la magia oscura profunda de Haskell?

+3

Probablemente deberías evitar 'fail' por completo, a menos que quieras personalizar el comportamiento en las coincidencias de patrones' do'-block 'que fallaron. – ehird

Respuesta

7

Bueno, fail se llama si se produce un fallo patrón-partido en un bloque do, como si tiene Just x <- something y el resultado something 's es Nothing. Aparte de eso, fail es una función normal.

Para el problema con strMsg "foo" = FooError etc., ¿ofrece throwError una interfaz más agradable para su caso de uso?

4

Este artículo puede ser útil: http://blog.ezyang.com/2011/08/8-ways-to-report-errors-in-haskell-revisited/

Su EitherT ya está en la biblioteca estándar y llamó ErrorT. Ver la documentación: http://hackage.haskell.org/packages/archive/mtl/latest/doc/html/Control-Monad-Error.html#t:ErrorT

fail es una curiosidad histórica ahora, y puede considerarse una falla de diseño, junto con la falta de Functor a => Monad a restricción. Es solo una característica controvertida manejar las coincidencias de patrones fallidos en la notación do.

throwError :: MonadError e m => e -> m a 

es el sustituto más común para fail, pero más están disponibles (ver el artículo).

Cuestiones relacionadas