module Control.Effects.Signal
( MonadEffectSignal(..), ResumeOrBreak(..), throwSignal, handleSignal
, Throws, handleException, handleToEither, module Control.Effects
, module Control.Monad.Trans.Except, MaybeT(..), discardAllExceptions, showAllExceptions
, Handles(..), handleToEitherRecursive, SomeSignal ) where
import Import
import Control.Monad.Trans.Except
import qualified GHC.TypeLits as TL
import GHC.TypeLits (TypeError, ErrorMessage(..))
import Control.Effects
import Control.Monad.Runnable
data Signal a b
type instance EffectMsg (Signal a b) = a
type instance EffectRes (Signal a b) = b
data SomeSignal = SomeSignal { getSomeSignal :: Text } deriving (Eq, Ord, Read, Show)
type family UnhandledError a b :: ErrorMessage where
UnhandledError a Void =
'TL.Text "Unhandled exception of type " ':<>: 'ShowType a
':$$: 'TL.Text "You need to handle all the exceptions before running the computation"
UnhandledError a b =
'TL.Text "Unhandled signal of type " ':<>: 'ShowType a
':<>: 'TL.Text " expecting a return value of type " ':<>: 'ShowType b
':$$: 'TL.Text "You need to handle all the signals before running the computation"
instance Monad m => MonadEffect (Signal e b) (ExceptT e m) where
effect _ = throwE
instance (Show e, Monad m) => MonadEffect (Signal e b) (ExceptT SomeSignal m) where
effect _ = throwE . SomeSignal . pack . show
instance Monad m => MonadEffect (Signal a b) (MaybeT m) where
effect _ _ = mzero
instance TypeError (UnhandledError a b)
=> MonadEffect (Signal a b) IO where
effect = undefined
class MonadEffect (Signal a b) m => MonadEffectSignal a b m where
signal :: a -> m b
signal = effect (Proxy :: Proxy (Signal a b))
type Throws e m = MonadEffectSignal e Void m
instance (Monad m, b ~ c) => MonadEffectSignal a c (EffectHandler (Signal a b) m)
instance Monad m => MonadEffectSignal a b (MaybeT m)
instance Monad m => MonadEffectSignal e b (ExceptT e m)
instance (Monad m, Show e) => MonadEffectSignal e b (ExceptT SomeSignal m)
instance MonadEffect (Signal a b) IO => MonadEffectSignal a b IO
instance (MonadEffectSignal a b m, MonadTrans t, Monad (t m))
=> MonadEffectSignal a b (t m)
data ResumeOrBreak b c = Resume b
| Break c
throwSignal :: Throws a m => a -> m b
throwSignal = fmap absurd . signal
resumeOrBreak :: (b -> a) -> (c -> a) -> ResumeOrBreak b c -> a
resumeOrBreak ba _ (Resume b) = ba b
resumeOrBreak _ ca (Break c) = ca c
collapseEither :: Either a a -> a
collapseEither (Left a) = a
collapseEither (Right a) = a
handleSignal :: Monad m
=> (a -> m (ResumeOrBreak b c))
-> EffectHandler (Signal a b) (ExceptT c m) c
-> m c
handleSignal f = fmap collapseEither
. runExceptT
. handleEffect (resumeOrBreak return throwE <=< lift . f)
handleException :: Monad m => (a -> m c) -> ExceptT a m c -> m c
handleException f = either f return <=< runExceptT
handleToEither :: ExceptT e m a -> m (Either e a)
handleToEither = runExceptT
discardAllExceptions :: MaybeT m a -> m (Maybe a)
discardAllExceptions = runMaybeT
mapLeft :: (a -> c) -> Either a b -> Either c b
mapLeft f (Left a) = Left (f a)
mapLeft _ (Right b) = Right b
showAllExceptions :: Functor m => ExceptT SomeSignal m a -> m (Either Text a)
showAllExceptions = fmap (mapLeft getSomeSignal) . runExceptT
class Throws e m => Handles e m where
handleRecursive :: (e -> m a) -> m a -> m a
instance Monad m => Handles e (ExceptT e m) where
handleRecursive f = ExceptT . (either (runExceptT . f) (return . Right) <=< runExceptT)
instance (Monad m, Monad (t m), Handles e m, RunnableTrans t)
=> Handles e (t m) where
handleRecursive f e = do
st <- currentTransState
res <- lift (handleRecursive (\ex -> runTransformer (f ex) st) (runTransformer e st))
restoreTransState res
handleToEitherRecursive :: Handles e m => m a -> m (Either e a)
handleToEitherRecursive = handleRecursive (return . Left) . fmap Right