haskell error-handling composition

haskell - Tipos de error expresivo y composable.



error-handling composition (1)

La biblioteca Control.Monad.Exception permite que se usen excepciones fuertemente tipadas en códigos que no sean de E / S. Esto permite a las funciones generar errores y componer fácilmente con funciones que generan diferentes errores. Por ejemplo:

{-# LANGUAGE RankNTypes, MultiParamTypeClasses, FunctionalDependencies #-} {-# LANGUAGE FlexibleInstances #-} import Prelude hiding (catch) import Control.Monad.Exception data FooException = FooException deriving (Show, Typeable) instance Exception FooException data BarErrors = BarErrors deriving (Show, Typeable) instance Exception BarErrors data BazErrors = BazErrors deriving (Show, Typeable) instance Exception BazErrors -- sample functions foo :: (Throws FooException l) => a -> EM l a foo a = return a bar :: (Throws BarErrors l) => a -> EM l a bar _ = throw BarErrors baz :: (Throws BazErrors l) => a -> EM l a baz a = return a -- using all at once: allAtOnce :: (Throws FooException l, Throws BarErrors l, Throws BazErrors l) => a -> EM l String allAtOnce x = do _ <- foo x _ <- bar x _ <- baz x return "success!" -- now running the code, catching the exceptions: run :: a -> String run x = runEM $ allAtOnce x `catch` (/(_ :: FooException) -> return "foo failed") `catch` (/BarErrors -> return "bar failed") `catch` (/BazErrors -> return "baz failed") -- run 3 results in "bar failed"

Para obtener más detalles sobre el uso de esta biblioteca, consulte también los documentos Excepciones tipificadas explícitamente para Haskell y Una jerarquía extensible tipificada dinámicamente de excepciones .

Estoy teniendo problemas con la mejor manera de informar errores en un conjunto de funciones que deberían componer bien, en una biblioteca en la que estoy trabajando.

Concretamente, tengo funciones que se parecen a:

foo, bar, baz :: a -> Maybe a

donde foo puede fallar de una sola manera (una buena opción para Maybe ), pero bar y baz pueden fallar de dos maneras diferentes cada una (una buena Either BarErrors para Either BarErrors y Either BazErrors ).

Una solución es crear:

data AllTheErrors = TheFooError | BarOutOfBeer | BarBurnedDown | ...

y haga que todas las funciones devuelvan Either AllTheErrors , que expresa el rango de errores que puede Either AllTheErrors una secuencia compuesta de estas funciones a expensas de expresar el rango de errores posibles para cada función individual .

¿Hay alguna manera de conseguir ambos? Tal vez con algo más que composición monádica? ¿O con familias tipo (olas de manos) ...?