{-# LANGUAGE DeriveFunctor, ExistentialQuantification, FlexibleContexts, FlexibleInstances, LambdaCase, MultiParamTypeClasses, StandaloneDeriving, TypeOperators, UndecidableInstances #-}
module Control.Effect.Error
( Error(..)
, throwError
, catchError
, runError
, ErrorC(..)
) where
import Control.Effect.Carrier
import Control.Effect.Sum
import Control.Effect.Internal
import Control.Monad ((<=<))
data Error exc m k
= Throw exc
| forall b . Catch (m b) (exc -> m b) (b -> k)
deriving instance Functor (Error exc m)
instance HFunctor (Error exc) where
hmap _ (Throw exc) = Throw exc
hmap f (Catch m h k) = Catch (f m) (f . h) k
instance Effect (Error exc) where
handle _ _ (Throw exc) = Throw exc
handle state handler (Catch m h k) = Catch (handler (m <$ state)) (handler . (<$ state) . h) (handler . fmap k)
throwError :: (Member (Error exc) sig, Carrier sig m) => exc -> m a
throwError = send . Throw
catchError :: (Member (Error exc) sig, Carrier sig m) => m a -> (exc -> m a) -> m a
catchError m h = send (Catch m h ret)
runError :: (Carrier sig m, Effect sig, Monad m) => Eff (ErrorC exc m) a -> m (Either exc a)
runError = runErrorC . interpret
newtype ErrorC e m a = ErrorC { runErrorC :: m (Either e a) }
instance (Carrier sig m, Effect sig, Monad m) => Carrier (Error e :+: sig) (ErrorC e m) where
ret a = ErrorC (pure (Right a))
eff = ErrorC . handleSum (eff . handleEither runErrorC) (\case
Throw e -> pure (Left e)
Catch m h k -> runErrorC m >>= either (either (pure . Left) (runErrorC . k) <=< runErrorC . h) (runErrorC . k))