Signals - louispan/pipes-fluid GitHub Wiki
Elm Signals
-
Deprecated in Jan 2016 https://github.com/evancz/elm-architecture-tutorial/tree/de5682a5a8e4459aed4637533adb25e462f8a2ae
-
But I still think it is useful
-
Another useful reference: FRP inspired “Controlling Time and Space: understanding the many formulations of FRP" by Evan Czaplicki) https://www.youtube.com/watch?v=Agu6jipKfYw
Main ideas
Signal a -- a effectful flow of values
Address a -- an inbox that can be sent values
Elm Signal a
corresponds to
Pipes.Concurrent.Input a
Monad m => Pipes.Producer a m ()
Elm Address a
corresponds to
Pipes.Concurrent.Output a
Monad m => Pipes.Consumer a m ()
Limitations of using Input a
for Signal a
:
liftA2 :: (a -> b -> c) ->
Signal a -> Signal b -> Signal c
- The
Applicative
instance ofInput a
only combines synchronously, ie. a value is returned only after both inputs produce a value.
Impulse
newtype Impulse m a = Impulse {
impulsively :: P.Producer a m () }
pipes-fluid
provides Impulse
with a Applicative instance that can reactively combines two producers, given initial values to use when the producer is blocked/failed.
- This only works for
Alternative m
where failure means there was no effects, eg.Control.Concurrent.STM
, orMonadTrans t => t STM
- NB.No monad instance
apImpulse :: (Alternative m, Monad m) =>
Maybe (a -> b) -> Maybe a
-> Impulse m (a -> b) -> Impulse m a -> Impulse m b
instance (Alternative m, Monad m) => Applicative (Impulse m)
where
pure = Impulse . P.yield -- “once”
-- 'ap' doesn't know about initial values
(<*>) = apImpulse Nothing Nothing
ImpulseIO
newtype ImpulseIO m a = ImpulseIO {
impulsivelyIO :: P.Producer a m () }
instance (MonadBaseControl IO m, Forall (A.Pure m)) => Applicative (ImpulseIO m)
- uses lifted-async package to run both producers in two lightweight threads.
Simultaneous
newtype Simultaneous m a = Simultaneous {
simultaneous :: P.Producer a m () }
- The applicative instance for
Simultaneous
will produce a value when both producers produce a value. - Functor, Applicative, and Monad instances for Simultaneous for all Monad m.
- NB. Can't use
Input a
because it is a newtype wrapper aroundSTM (Maybe a)
, notProducer a m ()
instance Monad m => Applicative (Simultaneous m) where
pure = Simultaneous . forever . P.yield -- constant/always
Simultaneous fs <*> Sync as = Simultaneous $ do
rf <- lift $ P.next fs
ra <- lift $ P.next as
case (rf, ra) of
(Left _, _) -> pure ()
(_, Left _) -> pure ()
(Right (f, fs'), Right (a, as')) -> do
P.yield $ f a
simultaneously $ Simultaneous fs' <*> Simultaneous as'