{-# LANGUAGE DeriveFunctor, DerivingStrategies, ExistentialQuantification, FlexibleContexts, FlexibleInstances, GeneralizedNewtypeDeriving, MultiParamTypeClasses, RankNTypes, StandaloneDeriving, TypeOperators, UndecidableInstances #-}
module Control.Effect.Resumable
(
Resumable(..)
, throwResumable
, SomeError(..)
, runResumable
, ResumableC(..)
, runResumableWith
, ResumableWithC(..)
, Carrier
, Member
, run
) where
import Control.Applicative (Alternative(..))
import Control.DeepSeq
import Control.Effect.Carrier
import Control.Effect.Error
import Control.Effect.Reader
import Control.Monad (MonadPlus(..))
import Control.Monad.Fail
import Control.Monad.Fix
import Control.Monad.IO.Class
import Control.Monad.Trans.Class
import Data.Functor.Classes
data Resumable err m k
= forall a . Resumable (err a) (a -> m k)
deriving instance Functor m => Functor (Resumable err m)
instance HFunctor (Resumable err) where
hmap f (Resumable err k) = Resumable err (f . k)
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 newtype (Alternative, Applicative, Functor, Monad, MonadFail, MonadFix, 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 newtype (Alternative, Applicative, Functor, Monad, MonadFail, MonadFix, 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 #-}