{-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE FunctionalDependencies #-} {-# LANGUAGE GADTs #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE UnicodeSyntax #-} module Control.Monad.Error.Hoist ( HoistError(..) , (<%?>) , (<%!?>) , () , () ) where import Control.Monad.Error.Class import Control.Monad.Trans.Either import Control.Monad.Trans -- | A tricky class for easily hoisting errors out of partiality types (e.g. -- 'Maybe', @'Either' e@) into a monad. The parameter @e@ represents the error -- information carried by the partiality type @t@, and @e'@ represents the type -- of error expected in the monad @m@. -- class Monad m ⇒ HoistError m t e e' | t → e where -- | Given a conversion from the error in @t α@ to @e'@, we can hoist the -- computation into @m@. -- hoistError ∷ (e → e') → t α → m α instance MonadError e m ⇒ HoistError m Maybe () e where hoistError f = maybe (throwError $ f ()) return instance MonadError e' m ⇒ HoistError m (Either e) e e' where hoistError f = either (throwError . f) return instance (m ~ n, MonadError e' m) ⇒ HoistError m (EitherT e n) e e' where hoistError f = eitherT (throwError . f) return -- | A flipped synonym for 'hoistError'. (<%?>) ∷ HoistError m t e e' ⇒ t α → (e → e') → m α (<%?>) = flip hoistError infixl 8 <%?> {-# INLINE (<%?>) #-} -- | A version of '<%?>' that operates on values already in the monad. -- (<%!?>) ∷ HoistError m t e e' ⇒ m (t α) → (e → e') → m α m <%!?> e = do x ← m x <%?> e infixl 8 <%!?> {-# INLINE (<%!?>) #-} -- | A version of @hoistError@ that ignores the error in @t α@ and replaces it -- with a new one in @e'@. -- () ∷ HoistError m t e e' ⇒ t α → e' → m α m e = m <%?> const e infixl 8 {-# INLINE () #-} -- | A version of @@ that operates on values already in the monad. () ∷ HoistError m t e e' ⇒ m (t α) → e' → m α m e = do x ← m x e infixl 8 {-# INLINE () #-}