packages feed

hoist-error-0.3.1.0: src/Control/Monad/Fail/Hoist.hs

{-# LANGUAGE FlexibleContexts #-}

-- | This module provides helpers for converting partiality types into
-- 'MonadFail' computations.
--
-- 'MonadFail''s purpose is to handle pattern-match failures in
-- @do@-expressions, and not to be a general-purpose error-handling
-- mechanism. Despite this, some libraries use it as one, and this
-- module can help you report errors via 'MonadFail'.
--
-- The operator mnemonics are the same as in
-- "Control.Monad.Error.Hoist", but with @#@ in place of @?@. You can
-- imagine a hastily-written @F@ looking kinda-sorta like a @#@, if it
-- helps.

module Control.Monad.Fail.Hoist
  ( hoistFail
  , hoistFail'
  , hoistFailM
  , hoistFailM'
  -- ** Operators
  , (<%#>)
  , (<%!#>)
  , (<#>)
  , (<!#>)
  ) where

import           Control.Monad.Error.Hoist  (PluckError(..))

-- | Given a conversion from the error in @t a@ to @String@, we can hoist the
-- computation into @m@.
--
-- @
-- 'hoistFail' :: 'MonadFail' m => (() -> String) -> 'Maybe'       a -> m a
-- 'hoistFail' :: 'MonadFail' m => (e  -> String) -> 'Either'  e   a -> m a
-- 'hoistFail' :: 'MonadFail' m => (e  -> String) -> 'ExceptT' e m a -> m a
-- @
--
-- @since 0.3.0.0
hoistFail
  :: (PluckError e t m, MonadFail m)
  => (e -> String)
  -> t a
  -> m a
hoistFail f = foldError (fail . f) pure

-- | @hoistFail' = hoistFail id@
--
-- @since 0.3.0.0
hoistFail' :: (PluckError String t m, MonadFail m) => t a -> m a
hoistFail' = hoistFail id

-- | A version of 'hoistFail' that operates on values already in the monad.
--
-- @
-- 'hoistFailM' :: 'MonadFail' m => (() -> String) -> m ('Maybe'       a) -> m a
-- 'hoistFailM' :: 'MonadFail' m => (e  -> String) -> m ('Either'  e   a) -> m a
-- 'hoistFailM' :: 'MonadFail' m => (e  -> String) -> m ('ExceptT' e m a) -> m a
-- @
--
-- @since 0.3.0.0
hoistFailM
  :: (PluckError e t m, MonadFail m)
  => (e -> String)
  -> m (t a)
  -> m a
hoistFailM f m = m >>= hoistFail f

-- | @hoistFailM' = hoistFailM id@
--
-- @since 0.3.0.0
hoistFailM'
  :: (PluckError String t m, MonadFail m)
  => m (t a)
  -> m a
hoistFailM' = hoistFailM id

-- | A flipped synonym for 'hoistFail'. Mnemonic: @#@ looks a bit like @F@.
--
-- @
-- ('<%#>') :: 'MonadFail' m => 'Maybe'       a -> (() -> String) -> m a
-- ('<%#>') :: 'MonadFail' m => 'Either'  e m a -> (e  -> String) -> m a
-- ('<%#>') :: 'MonadFail' m => 'ExceptT' e m a -> (e  -> String) -> m a
-- @
--
-- @since 0.3.0.0
(<%#>)
  :: (PluckError e t m, MonadFail m)
  => t a
  -> (e -> String)
  -> m a
(<%#>) = flip hoistFail

infixl 8 <%#>
{-# INLINE (<%#>) #-}

-- | A flipped synonym for 'hoistFailM'.
--
-- @
-- ('<%!#>') :: 'MonadFail' m => m ('Maybe'       a) -> (() -> String) -> m a
-- ('<%!#>') :: 'MonadFail' m => m ('Either'  e   a) -> (e  -> String) -> m a
-- ('<%!#>') :: 'MonadFail' m => m ('ExceptT' e m a) -> (e  -> String) -> m a
-- @
--
-- @since 0.3.0.0
(<%!#>)
  :: (PluckError e t m, MonadFail m)
  => m (t a)
  -> (e -> String)
  -> m a
(<%!#>) = flip hoistFailM

infixl 8 <%!#>
{-# INLINE (<%!#>) #-}

-- | A version of '<%#>' that ignores the error in @t a@ and fails
-- with a new one.
--
-- @
-- ('<#>') :: 'MonadFail' m => 'Maybe'       a -> String -> m a
-- ('<#>') :: 'MonadFail' m => 'Either'  e   a -> String -> m a
-- ('<#>') :: 'MonadFail' m => 'ExceptT' e m a -> String -> m a
-- @
--
-- @since 0.3.0.0
(<#>)
  :: (PluckError e t m, MonadFail m)
  => t a
  -> String
  -> m a
m <#> e = m <%#> const e

infixl 8 <#>
{-# INLINE (<#>) #-}

-- | A version of '<#>' that operates on values already in the monad.
--
-- @
-- ('<!#>') :: 'MonadFail' m => m ('Maybe'       a) -> String -> m a
-- ('<!#>') :: 'MonadFail' m => m ('Either'  e   a) -> String -> m a
-- ('<!#>') :: 'MonadFail' m => m ('ExceptT' e m a) -> String -> m a
-- @
--
-- @since 0.3.0.0
(<!#>)
  :: (PluckError e t m, MonadFail m)
  => m (t a)
  -> String
  -> m a
m <!#> e = m >>= hoistFail (const e)

infixl 8 <!#>
{-# INLINE (<!#>) #-}