packages feed

raft-0.3.11.0: src/Control/Monad/Except/Util.hs

-----------------------------------------------------------------------------
--
-- Module      :  Control.Monad.Except.Util
-- Copyright   :  (c) 2016 Brian W Bush
-- License     :  MIT
--
-- Maintainer  :  Brian W Bush <consult@brianwbush.info>
-- Stability   :  Stable
-- Portability :  Portable
--
-- | Utilities related to the <https://hackage.haskell.org/package/mtl mtl> package.
--
-----------------------------------------------------------------------------


{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE Safe             #-}


module Control.Monad.Except.Util (
-- * Assertions
  assert
, deny
-- * Input/Output
, tryIO
, guardIO
, eitherError
, runToIO
) where


import Control.Exception (IOException, throw, try)
import Control.Monad (unless, when)
import Control.Monad.Except (ExceptT, MonadError, MonadIO, liftIO, runExceptT, throwError)
import Data.String (IsString(..))
import System.IO.Error (tryIOError)


-- | Attempt an IO action.
tryIO :: (IsString e, MonadError e m, MonadIO m) => IO a -> m a
tryIO = (>>= either (\e -> throwError . fromString $ show (e :: IOException)) return) . liftIO . try


-- | Catch 'Control.Exception.IOException' and throw it into 'MonadError String'.  Derived from <http://chromaticleaves.com/posts/guard-io-with-errort.html>.
guardIO :: (MonadIO m, MonadError String m) => IO a -> m a
guardIO =
  (either (throwError . show) return =<<)
    . liftIO
    . tryIOError


-- | Throw 'Data.Either.Left' into 'Control.Exception.IOException'.
eitherError :: (a -> b) -> Either String a -> IO b
eitherError f = either (throw . userError) (return . f)


-- | Run 'Control.Monad.Except.ExceptT' to 'System.IO'.
runToIO :: ExceptT String IO a -> IO a
runToIO = (eitherError id =<<) . runExceptT


-- | Make an assertion.
assert :: (IsString e, MonadError e m) => e -> Bool -> m ()
assert = flip unless . throwError


-- | Make a denial.
deny :: (IsString e, MonadError e m) => e -> Bool -> m ()
deny = flip when . throwError