{-# LANGUAGE DeriveFunctor, ExistentialQuantification, FlexibleContexts, FlexibleInstances, GeneralizedNewtypeDeriving, KindSignatures, MultiParamTypeClasses, RankNTypes, StandaloneDeriving, TypeOperators, UndecidableInstances #-}
module Control.Effect.Resumable
( Resumable(..)
, throwResumable
, SomeError(..)
, runResumable
, ResumableC(..)
, runResumableWith
, ResumableWithC(..)
) where
import Control.Applicative (Alternative(..))
import Control.DeepSeq
import Control.Effect.Carrier
import Control.Effect.Error
import Control.Effect.Reader
import Control.Effect.Sum
import Control.Monad (MonadPlus(..))
import Control.Monad.Fail
import Control.Monad.IO.Class
import Control.Monad.Trans.Class
import Data.Coerce
import Data.Functor.Classes
data Resumable err (m :: * -> *) k
= forall a . Resumable (err a) (a -> k)
deriving instance Functor (Resumable err m)
instance HFunctor (Resumable err) where
hmap _ = coerce
{-# INLINE hmap #-}
instance Effect (Resumable err) where
handle state handler (Resumable err k) = Resumable err (handler . (<$ state) . k)
throwResumable :: (Member (Resumable err) sig, Carrier sig m) => err a -> m a
throwResumable err = send (Resumable err pure)
data SomeError (err :: * -> *)
= forall a . SomeError (err a)
instance Eq1 err => Eq (SomeError err) where
SomeError exc1 == SomeError exc2 = liftEq (const (const True)) exc1 exc2
instance Ord1 err => Ord (SomeError err) where
SomeError exc1 `compare` SomeError exc2 = liftCompare (const (const EQ)) exc1 exc2
instance Show1 err => Show (SomeError err) where
showsPrec d (SomeError err) = showsUnaryWith (liftShowsPrec (const (const id)) (const id)) "SomeError" d err
instance NFData1 err => NFData (SomeError err) where
rnf (SomeError err) = liftRnf (\a -> seq a ()) err
runResumable :: ResumableC err m a -> m (Either (SomeError err) a)
runResumable = runError . runResumableC
newtype ResumableC err m a = ResumableC { runResumableC :: ErrorC (SomeError err) m a }
deriving (Alternative, Applicative, Functor, Monad, MonadFail, MonadIO, MonadPlus, MonadTrans)
instance (Carrier sig m, Effect sig) => Carrier (Resumable err :+: sig) (ResumableC err m) where
eff (L (Resumable err _)) = ResumableC (throwError (SomeError err))
eff (R other) = ResumableC (eff (R (handleCoercible other)))
{-# INLINE eff #-}
runResumableWith :: (forall x . err x -> m x)
-> ResumableWithC err m a
-> m a
runResumableWith with = runReader (Handler with) . runResumableWithC
newtype ResumableWithC err m a = ResumableWithC { runResumableWithC :: ReaderC (Handler err m) m a }
deriving (Alternative, Applicative, Functor, Monad, MonadFail, MonadIO, MonadPlus)
instance MonadTrans (ResumableWithC err) where
lift = ResumableWithC . lift
{-# INLINE lift #-}
newtype Handler err m = Handler { runHandler :: forall x . err x -> m x }
instance Carrier sig m => Carrier (Resumable err :+: sig) (ResumableWithC err m) where
eff (L (Resumable err k)) = ResumableWithC (ReaderC (\ handler -> runHandler handler err)) >>= k
eff (R other) = ResumableWithC (eff (R (handleCoercible other)))
{-# INLINE eff #-}