failable 1.0.0.0 → 1.1.0.0
raw patch · 2 files changed
+29/−35 lines, 2 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
- Control.Monad.Failable: hoistEither :: (Failable m, Exception e) => (a -> e) -> Either a b -> m b
- Control.Monad.Failable: hoistMaybe :: (Failable m, Exception e) => e -> Maybe a -> m a
+ Control.Monad.Failable: class (Failable m) => Hoistable m t e' | t -> e'
+ Control.Monad.Failable: hoist :: (Hoistable m t e', Exception e) => (e' -> e) -> t a -> m a
+ Control.Monad.Failable: instance Control.Monad.Failable.Failable m => Control.Monad.Failable.Hoistable m (Data.Either.Either e') e'
+ Control.Monad.Failable: instance Control.Monad.Failable.Failable m => Control.Monad.Failable.Hoistable m GHC.Maybe.Maybe ()
Files
- failable.cabal +2/−2
- src/Control/Monad/Failable.hs +27/−33
failable.cabal view
@@ -4,10 +4,10 @@ -- -- see: https://github.com/sol/hpack ----- hash: 802186e92dd2e28073f828c705992da99962737bcc8ef0e229e7a0f10fe02697+-- hash: 2156677b8596bc4da7b62af27300220dff65805690fad23c10ac51895c635b4b name: failable-version: 1.0.0.0+version: 1.1.0.0 synopsis: A 'Failable' error monad class to unify failure across monads that can fail description: This library contains a 'Failable' error monad class to unify failure across monads and transformers most commonly used to implement pipelines that can fail and does so in a simple nonsense way by providing the means of signaling a computation "failure" while striving to keep the failure behaviour consistent with the actual definition of the monad/transformer. Please refer to the README file for a more elaborate description and some examples. category: control, exceptions, monad
src/Control/Monad/Failable.hs view
@@ -1,4 +1,4 @@-{-# LANGUAGE GADTs #-}+{-# LANGUAGE FlexibleInstances, FunctionalDependencies, GADTs, MultiParamTypeClasses #-} {- | Module: Control.Monad.Failable Description: Yet another error monad but for people who are not crazy@@ -62,7 +62,7 @@ -- >>> runMaybeT $ foo 2 :: IO (Maybe Int) -- >>> Nothing --- Failable(..), failableIO, hoistEither, hoistMaybe) where+ Failable(..), Hoistable(..), failableIO) where import Control.Exception (Exception(..), SomeException(..), throw, catch) import Control.Monad (join)@@ -84,6 +84,27 @@ -- | recover from a possible failure. Basically a generalized @catch@ for a @Failable@. recover :: (e ~ SomeException) => m a -> (e -> m a) -> m a ++-- | A 'Hoistable' is a type that can be "promoted" or "hoisted" to a Failable monad.+class (Failable m) => Hoistable m t e' | t -> e' where+ -- | Given a transformation function to obtain an error in the target 'Failable' context from+ -- an eventual errored value from the value being hoisted, It promotes such value to a 'Failable'+ -- operation. For example:+ --+ -- @+ -- foo :: (Failable m) => String -> m Int+ -- foo = hoist BadValue . readEither+ -- @+ --+ -- >>> λ> runExceptT $ foo "5"+ -- >>> Right 5+ -- >>> λ> foo "X5"+ -- >>> *** Exception: BadValue "Prelude.read: no parse"+ -- >>> λ> runMaybeT $ foo "X5"+ -- >>> Nothing+ --+ hoist :: (Exception e) => (e' -> e) -> t a -> m a+ instance Failable IO where failure = throw recover = catch@@ -115,38 +136,11 @@ where recover' (Left err) = runExceptT $ f err recover' x = return x --- | "Promote" a 'Maybe' into a 'Failable' context. Useful to reduce boilerplate when using--- functions that might return a 'Maybe' type. If the value is @Nothing@, the error specified is then--- triggered in the 'Failable' context-hoistMaybe :: (Failable m, Exception e) => e -> Maybe a -> m a-hoistMaybe err = maybe (failure err) return+instance (Failable m) => Hoistable m Maybe () where+ hoist f = maybe (failure $ f ()) return --- | "Promote" an 'Either' value into a 'Failable' context. Useful to reduce verbosity when using--- functions that return an 'Either' type. If the value is @Left err@, the wrapped error is then passed--- as an argument to the provided function which should return an instance of 'Exception'.--- so for example:------ @--- data MyErrors = BadValue deriving (Typeable, Show)--- instance Exception MyErrors------ foo :: (Failable m) => String -> m Int--- foo = hoistEither BadValue . readEither--- @------ >>> λ> foo "5" :: Maybe Int--- >>> Just 5--- >>> λ> foo "5" :: Either SomeException Int--- >>> Right 5--- >>> λ> foo "X5" :: Either SomeException Int--- >>> Left (BadValue "Prelude.read: no parse")--- >>> λ> foo "5" :: Maybe Int--- >>> Just 5--- >>> λ> foo "X5" :: Maybe Int--- >>> Nothing----hoistEither :: (Failable m, Exception e) => (a -> e) -> Either a b -> m b-hoistEither f = either (failure . f) return+instance (Failable m) => Hoistable m (Either e') e' where+ hoist f = either (failure . f) return -- | Perform a set of IO actions in a 'Failable' 'MonadIO' instance, triggering a -- 'failure' upon an IO exception, instead of blindly triggering an asynchronos exception. This