open-signals-0.1.0.3: A mechanism similar to checked exceptions that integrates with MTL and transformer stacks

Safe HaskellNone
LanguageHaskell2010

Control.Monad.Signal.Class

Description

Some sample usage could look like this.

   sample :: (Subset' '[Int, String] sigs, MonadSignal sigs m, MonadIO m) => m ()
   sample = do
       liftIO (putStrLn "Signaling 1")
       signal (1 :: Int)
       liftIO (putStrLn "Signaling asd")
       signal "asd"

   sample' :: (MonadSignal '[Int, String] m, MonadIO m) => m ()
   sample' = handleOne (\(i :: String) -> liftIO (putStrLn i) >> signal i) return sample

You can then try errorAllSignals sample' in GHCi to see what happens. Then try commenting out the signal (1 :: Int) line.

Notice that both functions are polymorphic in the monad they're running in. The handleOne function discards one signal from the constraint on m by extracting it into an EitherT and it leaves the rest of them in the polymorphic underlying monad. This lets us write MTL style code while still being able to do insteresting things with the types.

Synopsis

Documentation

class Monad m => MonadSignal sigs m | m -> sigs where Source

A class of monads that can signal a value with a type from some fixed set of types. Implementing instances for any transformer should be as easy as

    signal = lift . signal
    signalUnion = lift . signalUnion

Minimal complete definition

signalUnion

Methods

signal :: Elem sigs s => s -> m a Source

signalUnion :: Union sigs -> m a Source

Instances

MonadSignal sigs m => MonadSignal sigs (MaybeT m) Source 
MonadSignal sigs (Signal sigs) Source 
MonadSignal sigs m => MonadSignal sigs (ContT r m) Source 
MonadSignal sigs m => MonadSignal sigs (StateT s m) Source 
(MonadSignal sigs m, Monoid w) => MonadSignal sigs (WriterT w m) Source 
MonadSignal sigs m => MonadSignal sigs (ReaderT r m) Source 
Monad m => MonadSignal sigs (SignalT sigs m) Source 
MonadSignal ([] *) IO Source 
MonadSignal sigs m => MonadSignal ((:) * s sigs) (EitherT s m) Source 

handleOne :: MonadSignal sigs m => (s -> m b) -> (a -> m b) -> EitherT s m a -> m b Source

Handle a single signal. This function takes an EitherT but since there's a MonadSignal instance for EitherT it's very easy to use if your functions are polymorphic over monads.

type family Subset' as bs :: Constraint Source

Basically Subset' '[a1, a2,...] bs is an alias for (Elem a1 bs, Elem a2 bs,...)

Equations

Subset' `[]` bs = () 
Subset' (a : as) bs = (Elem bs a, Subset' as bs) 

handleAll :: (Monad m, All c sigs) => proxy c -> (forall x. c x => x -> m a) -> SignalT sigs m a -> m a Source

If all the elements of sigs satisfy the c constraint then, given a function that only cares about that constraint type, we can colapse the signal transformer into the underlying monad.

For example, if all the types in sigs satisfy the Show class, then we can use the show function to turn a SignalT sigs m String into a m String.

throwAllSignals :: (MonadIO m, All Exception sigs) => SignalT sigs m a -> m a Source

If all the signals are exceptions, we can throw them as IO exceptions.

errorAllSignals :: (Monad m, All Show sigs) => SignalT sigs m a -> m a Source

If all the signals are showable we can crash with an error for any of them.

liftSignals :: forall sigs sigs' m a. (All (Elem sigs') sigs, MonadSignal sigs' m) => SignalT sigs m a -> m a Source

This is useful if we have a function like MonadSignal '[A, B] m => m () and we want to use it in something like MonadSignal '[B, C, A] m => m ().

newtype SignalT sigs m a Source

A transformer version of Signal.

Constructors

SignalT 

Fields

runSignalT :: m (Signal sigs a)
 

Instances

MonadState s m => MonadState s (SignalT sigs m) Source 
MonadWriter w m => MonadWriter w (SignalT sigs m) Source 
MonadReader r m => MonadReader r (SignalT sigs m) Source 
Monad m => MonadSignal sigs (SignalT sigs m) Source 
MonadTrans (SignalT sigs) Source 
Monad m => Monad (SignalT sigs m) Source 
Functor m => Functor (SignalT sigs m) Source 
MonadFix m => MonadFix (SignalT sigs m) Source

Not sure if correct

Applicative m => Applicative (SignalT sigs m) Source 
Foldable m => Foldable (SignalT sigs m) Source 
Traversable m => Traversable (SignalT sigs m) Source 
MonadIO m => MonadIO (SignalT sigs m) Source 
MonadCont m => MonadCont (SignalT sigs m) Source 
Eq (m (Signal sigs a)) => Eq (SignalT sigs m a) Source 
Ord (m (Signal sigs a)) => Ord (SignalT sigs m a) Source 
Read (m (Signal sigs a)) => Read (SignalT sigs m a) Source 
Show (m (Signal sigs a)) => Show (SignalT sigs m a) Source 

data Signal sigs a Source

A Signal sigs a is either a Union sigs or a value of type a. It's basically the same as Union (a ': sigs) but the a parameter is special because it's used in the Functor/Applicative/Monad instances.k

Constructors

Value a 
Signal (Union sigs) 

Instances

MonadSignal sigs (Signal sigs) Source 
Monad (Signal sigs) Source 
Functor (Signal sigs) Source 
Applicative (Signal sigs) Source 
Foldable (Signal sigs) Source 
Traversable (Signal sigs) Source 
(Eq a, Eq (Union sigs)) => Eq (Signal sigs a) Source 
(Ord a, Ord (Union sigs)) => Ord (Signal sigs a) Source 
(Read a, Read (Union sigs)) => Read (Signal sigs a) Source 
(ShowSignal sigs, Show a) => Show (Signal sigs a) Source