{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE NoMonomorphismRestriction #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE Safe #-}
module Control.Eff.Exception ( Exc (..)
, Fail
, throwError
, throwError_
, die
, runError
, runFail
, catchError
, onFail
, rethrowError
, liftEither
, liftEitherM
, liftMaybe
, liftMaybeM
, ignoreFail
) where
import Control.Eff.Internal
import Data.OpenUnion
import Control.Monad (void)
import Control.Monad.Base
import Control.Monad.Trans.Control
newtype Exc e v = Exc e
instance ( MonadBase m m
, SetMember Lift (Lift m) r
, MonadBaseControl m (Eff r)
) => MonadBaseControl m (Eff (Exc e ': r)) where
type StM (Eff (Exc e ': r)) a = StM (Eff r) (Either e a)
liftBaseWith f = raise $ liftBaseWith $ \runInBase ->
f (runInBase . runError)
restoreM x = do r :: Either e a <- raise (restoreM x)
liftEither r
type Fail = Exc ()
throwError :: (Member (Exc e) r) => e -> Eff r a
throwError e = send (Exc e)
{-# INLINE throwError #-}
throwError_ :: (Member (Exc e) r) => e -> Eff r ()
throwError_ = throwError
{-# INLINE throwError_ #-}
die :: Member Fail r => Eff r a
die = throwError ()
{-# INLINE die #-}
runError :: Eff (Exc e ': r) a -> Eff r (Either e a)
runError = handle_relay
(return . Right)
(\(Exc e) _k -> return (Left e))
runFail :: Eff (Fail ': r) a -> Eff r (Maybe a)
runFail = fmap (either (const Nothing) Just) . runError
{-# INLINE runFail #-}
catchError :: Member (Exc e) r =>
Eff r a -> (e -> Eff r a) -> Eff r a
catchError m handle = interpose return (\(Exc e) _k -> handle e) m
onFail :: Eff (Fail ': r) a
-> Eff r a
-> Eff r a
onFail e handle = runFail e >>= maybe handle return
{-# INLINE onFail #-}
rethrowError :: (Member (Exc e') r)
=> (e -> e')
-> Eff (Exc e ': r) a
-> Eff r a
rethrowError t eff = runError eff >>= either (throwError . t) return
liftEither :: (Member (Exc e) r) => Either e a -> Eff r a
liftEither = either throwError return
{-# INLINE liftEither #-}
liftEitherM :: (Member (Exc e) r, SetMember Lift (Lift m) r)
=> m (Either e a)
-> Eff r a
liftEitherM m = lift m >>= liftEither
{-# INLINE liftEitherM #-}
liftMaybe :: Member Fail r => Maybe a -> Eff r a
liftMaybe = maybe die return
{-# INLINE liftMaybe #-}
liftMaybeM :: (Member Fail r, SetMember Lift (Lift m) r)
=> m (Maybe a)
-> Eff r a
liftMaybeM m = lift m >>= liftMaybe
{-# INLINE liftMaybeM #-}
ignoreFail :: Eff (Fail ': r) a
-> Eff r ()
ignoreFail e = void e `onFail` return ()
{-# INLINE ignoreFail #-}