Safe Haskell | None |
---|---|
Language | Haskell2010 |
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.
- class Monad m => MonadSignal sigs m | m -> sigs where
- signal :: Elem sigs s => s -> m a
- signalUnion :: Union sigs -> m a
- handleOne :: MonadSignal sigs m => (s -> m b) -> (a -> m b) -> EitherT s m a -> m b
- type family Subset' as bs :: Constraint
- handleAll :: (Monad m, All c sigs) => proxy c -> (forall x. c x => x -> m a) -> SignalT sigs m a -> m a
- throwAllSignals :: (MonadIO m, All Exception sigs) => SignalT sigs m a -> m a
- errorAllSignals :: (Monad m, All Show sigs) => SignalT sigs m a -> m a
- liftSignals :: forall sigs sigs' m a. (All (Elem sigs') sigs, MonadSignal sigs' m) => SignalT sigs m a -> m a
- newtype SignalT sigs m a = SignalT {
- runSignalT :: m (Signal sigs a)
- data Signal sigs a
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
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,...)
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
.
SignalT | |
|
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 |
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
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 |