rhine-1.8: src/FRP/Rhine/Reactimation/Combinators.hs
{-# LANGUAGE ExistentialQuantification #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE TypeFamilies #-}
{- |
Combinators to create 'Rhine's (main programs) from basic components
such as 'ClSF's, clocks, 'ResamplingBuffer's and 'Schedule's.
The combinator names are often mixed of the symbols @, @*@ and @>@,
and several other symbols.
The general mnemonic for combinator names is:
* @ annotates a data processing unit such as a signal function, network or buffer
with temporal information like a clock or a schedule.
* @*@ composes parallely.
* @>@ composes sequentially.
-}
module FRP.Rhine.Reactimation.Combinators where
-- rhine
import FRP.Rhine.ClSF.Core
import FRP.Rhine.Clock
import FRP.Rhine.Clock.Proxy
import FRP.Rhine.ResamplingBuffer
import FRP.Rhine.SN
import FRP.Rhine.SN.Combinators
import FRP.Rhine.Schedule
import FRP.Rhine.Type
-- * Combinators and syntactic sugar for high-level composition of signal networks.
infix 5 @@
{- FOURMOLU_DISABLE -}
{- | Create a synchronous 'Rhine' by combining a clocked signal function with a matching clock.
Synchronicity is ensured by requiring that data enters (@In cl@)
and leaves (@Out cl@) the system at the same as it is processed (@cl@).
-}
(@@) ::
( cl ~ In cl
, cl ~ Out cl
, Monad m
, Clock m cl
, GetClockProxy cl
) =>
ClSF m cl a b ->
cl ->
Rhine m cl a b
(@@) = Rhine . synchronous
{-# INLINE (@@) #-}
{- | A purely syntactical convenience construction
enabling quadruple syntax for sequential composition, as described below.
-}
infix 2 >--
data RhineAndResamplingBuffer m cl1 inCl2 a c
= forall b.
RhineAndResamplingBuffer (Rhine m cl1 a b) (ResamplingBuffer m (Out cl1) inCl2 b c)
-- | Syntactic sugar for 'RhineAndResamplingBuffer'.
(>--) ::
Rhine m cl1 a b ->
ResamplingBuffer m (Out cl1) inCl2 b c ->
RhineAndResamplingBuffer m cl1 inCl2 a c
(>--) = RhineAndResamplingBuffer
{- | The combinators for sequential composition allow for the following syntax:
@
rh1 :: Rhine m cl1 a b
rh1 = ...
rh2 :: Rhine m cl2 c d
rh2 = ...
rb :: ResamplingBuffer m (Out cl1) (In cl2) b c
rb = ...
rh :: Rhine m (SequentialClock cl1 cl2) a d
rh = rh1 >-- rb --> rh2
@
-}
infixr 1 -->
(-->) ::
( Clock m cl1
, Clock m cl2
, Monad m
, Time cl1 ~ Time cl2
, Time (Out cl1) ~ Time cl1
, Time (In cl2) ~ Time cl2
, Clock m (Out cl1), Clock m (Out cl2)
, Clock m (In cl1), Clock m (In cl2)
, In cl2 ~ inCl2
, GetClockProxy cl1, GetClockProxy cl2
) =>
RhineAndResamplingBuffer m cl1 inCl2 a b ->
Rhine m cl2 b c ->
Rhine m (SequentialClock cl1 cl2) a c
RhineAndResamplingBuffer (Rhine sn1 cl1) rb --> (Rhine sn2 cl2) =
Rhine (sequential sn1 rb sn2) (SequentialClock cl1 cl2)
{- | The combinators for parallel composition allow for the following syntax:
@
rh1 :: Rhine m clL a b
rh1 = ...
rh2 :: Rhine m clR a c
rh2 = ...
rh :: Rhine m (ParallelClock clL clR) a (Either b c)
rh = rh1 +\@+ rh2
@
-}
infix 3 +@+
(+@+) ::
( Monad m, Clock m clL, Clock m clR
, Clock m (Out clL), Clock m (Out clR)
, GetClockProxy clL, GetClockProxy clR
, Time clL ~ Time (Out clL), Time clR ~ Time (Out clR)
, Time clL ~ Time (In clL), Time clR ~ Time (In clR)
, Time clL ~ Time clR
) =>
Rhine m clL a b ->
Rhine m clR a c ->
Rhine m (ParallelClock clL clR) a (Either b c)
Rhine sn1 clL +@+ Rhine sn2 clR =
Rhine (sn1 ++++ sn2) (ParallelClock clL clR)
{- | The combinators for parallel composition allow for the following syntax:
@
rh1 :: Rhine m clL a b
rh1 = ...
rh2 :: Rhine m clR a b
rh2 = ...
rh :: Rhine m (ParallelClock clL clR) a b
rh = rh1 |\@| rh2
@
-}
infix 3 |@|
(|@|) ::
( Monad m
, Clock m clL
, Clock m clR
, Clock m (Out clL)
, Clock m (Out clR)
, GetClockProxy clL
, GetClockProxy clR
, Time clL ~ Time (Out clL)
, Time clR ~ Time (Out clR)
, Time clL ~ Time (In clL)
, Time clR ~ Time (In clR)
, Time clL ~ Time clR
) =>
Rhine m clL a b ->
Rhine m clR a b ->
Rhine m (ParallelClock clL clR) a b
Rhine sn1 clL |@| Rhine sn2 clR =
Rhine (sn1 |||| sn2) (ParallelClock clL clR)
-- | Postcompose a 'Rhine' with a pure function.
(@>>^) ::
Monad m =>
Rhine m cl a b ->
(b -> c) ->
Rhine m cl a c
Rhine sn cl @>>^ f = Rhine (sn >>>^ f) cl
-- | Precompose a 'Rhine' with a pure function.
(^>>@) ::
Monad m =>
(a -> b) ->
Rhine m cl b c ->
Rhine m cl a c
f ^>>@ Rhine sn cl = Rhine (f ^>>> sn) cl
-- | Postcompose a 'Rhine' with a 'ClSF'.
(@>-^) ::
( Clock m (Out cl), GetClockProxy cl, Monad m
, Time cl ~ Time (Out cl)
) =>
Rhine m cl a b ->
ClSF m (Out cl) b c ->
Rhine m cl a c
Rhine sn cl @>-^ clsf = Rhine (sn >--^ clsf) cl
-- | Precompose a 'Rhine' with a 'ClSF'.
(^->@) ::
( Clock m (In cl), GetClockProxy cl, Monad m
, Time cl ~ Time (In cl)
) =>
ClSF m (In cl) a b ->
Rhine m cl b c ->
Rhine m cl a c
clsf ^->@ Rhine sn cl = Rhine (clsf ^--> sn) cl
{- FOURMOLU_ENABLE -}