{-# 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
  ) =>
  ClSF  m cl a b ->
          cl     ->
  Rhine m cl a b
@@ :: forall cl (m :: Type -> Type) a b.
(cl ~ In cl, cl ~ Out cl) =>
ClSF m cl a b -> cl -> Rhine m cl a b
(@@) = forall (m :: Type -> Type) cl a b.
SN m cl a b -> cl -> Rhine m cl a b
Rhine forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall cl (m :: Type -> Type) a b.
(cl ~ In cl, cl ~ Out cl) =>
ClSF m cl a b -> SN m cl a b
Synchronous

{- | 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
>-- :: forall (m :: Type -> Type) cl1 a b inCl2 c.
Rhine m cl1 a b
-> ResamplingBuffer m (Out cl1) inCl2 b c
-> RhineAndResamplingBuffer m cl1 inCl2 a c
(>--) = forall (m :: Type -> Type) cl1 inCl2 a c b.
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
  , 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 SN m cl1 a b
sn1 cl1
cl1) ResamplingBuffer m (Out cl1) inCl2 b b
rb --> :: forall (m :: Type -> Type) cl1 cl2 inCl2 a b c.
(Clock m cl1, Clock m cl2, 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
--> (Rhine SN m cl2 b c
sn2 cl2
cl2) =
  forall (m :: Type -> Type) cl a b.
SN m cl a b -> cl -> Rhine m cl a b
Rhine (forall (m :: Type -> Type) clab clcd a b c d.
(Clock m clab, Clock m clcd, Clock m (Out clab),
 Clock m (Out clcd), Clock m (In clab), Clock m (In clcd),
 GetClockProxy clab, GetClockProxy clcd, Time clab ~ Time clcd,
 Time clab ~ Time (Out clab), Time clcd ~ Time (In clcd)) =>
SN m clab a b
-> ResamplingBuffer m (Out clab) (In clcd) b c
-> SN m clcd c d
-> SN m (SequentialClock clab clcd) a d
Sequential SN m cl1 a b
sn1 ResamplingBuffer m (Out cl1) inCl2 b b
rb SN m cl2 b c
sn2) (forall cl1 cl2.
(Time cl1 ~ Time cl2) =>
cl1 -> cl2 -> SequentialClock cl1 cl2
SequentialClock cl1
cl1 cl2
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 SN m clL a b
sn1 clL
clL +@+ :: forall (m :: Type -> Type) clL clR a b c.
(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 SN m clR a c
sn2 clR
clR =
  forall (m :: Type -> Type) cl a b.
SN m cl a b -> cl -> Rhine m cl a b
Rhine (SN m clL a b
sn1 forall (m :: Type -> Type) clL clR a b c.
(Monad m, Clock m clL, Clock m clR, Clock m (Out clL),
 Clock m (Out clR), GetClockProxy clL, GetClockProxy clR,
 Time clL ~ Time clR, Time clL ~ Time (Out clL),
 Time clL ~ Time (In clL), Time clR ~ Time (Out clR),
 Time clR ~ Time (In clR)) =>
SN m clL a b
-> SN m clR a c -> SN m (ParClock clL clR) a (Either b c)
++++ SN m clR a c
sn2) (forall cl1 cl2.
(Time cl1 ~ Time cl2) =>
cl1 -> cl2 -> ParallelClock cl1 cl2
ParallelClock clL
clL clR
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 SN m clL a b
sn1 clL
clL |@| :: forall (m :: Type -> Type) clL clR a b.
(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 SN m clR a b
sn2 clR
clR =
  forall (m :: Type -> Type) cl a b.
SN m cl a b -> cl -> Rhine m cl a b
Rhine (SN m clL a b
sn1 forall (m :: Type -> Type) clL clR a b.
(Monad m, Clock m clL, Clock m clR, Clock m (Out clL),
 Clock m (Out clR), GetClockProxy clL, GetClockProxy clR,
 Time clL ~ Time clR, Time clL ~ Time (Out clL),
 Time clL ~ Time (In clL), Time clR ~ Time (Out clR),
 Time clR ~ Time (In clR)) =>
SN m clL a b -> SN m clR a b -> SN m (ParClock clL clR) a b
|||| SN m clR a b
sn2) (forall cl1 cl2.
(Time cl1 ~ Time cl2) =>
cl1 -> cl2 -> ParallelClock cl1 cl2
ParallelClock clL
clL clR
clR)

-- | Postcompose a 'Rhine' with a pure function.
(@>>^) ::
  Monad m =>
  Rhine m cl a b       ->
              (b -> c) ->
  Rhine m cl a      c
Rhine SN m cl a b
sn cl
cl @>>^ :: forall (m :: Type -> Type) cl a b c.
Monad m =>
Rhine m cl a b -> (b -> c) -> Rhine m cl a c
@>>^ b -> c
f = forall (m :: Type -> Type) cl a b.
SN m cl a b -> cl -> Rhine m cl a b
Rhine (SN m cl a b
sn forall (m :: Type -> Type) cl a b c.
Monad m =>
SN m cl a b -> (b -> c) -> SN m cl a c
>>>^ b -> c
f) cl
cl

-- | Precompose a 'Rhine' with a pure function.
(^>>@) ::
  Monad m =>
            (a -> b)  ->
  Rhine m cl      b c ->
  Rhine m cl a      c
a -> b
f ^>>@ :: forall (m :: Type -> Type) a b cl c.
Monad m =>
(a -> b) -> Rhine m cl b c -> Rhine m cl a c
^>>@ Rhine SN m cl b c
sn cl
cl = forall (m :: Type -> Type) cl a b.
SN m cl a b -> cl -> Rhine m cl a b
Rhine (a -> b
f forall (m :: Type -> Type) a b cl c.
Monad m =>
(a -> b) -> SN m cl b c -> SN m cl a c
^>>> SN m cl b c
sn) cl
cl

-- | Postcompose a 'Rhine' with a 'ClSF'.
(@>-^) ::
  ( Clock m (Out cl)
  , Time cl ~ Time (Out cl)
  ) =>
  Rhine m      cl  a b   ->
  ClSF  m (Out cl)   b c ->
  Rhine m      cl  a   c
Rhine SN m cl a b
sn cl
cl @>-^ :: forall (m :: Type -> Type) cl a b c.
(Clock m (Out cl), Time cl ~ Time (Out cl)) =>
Rhine m cl a b -> ClSF m (Out cl) b c -> Rhine m cl a c
@>-^ ClSF m (Out cl) b c
clsf = forall (m :: Type -> Type) cl a b.
SN m cl a b -> cl -> Rhine m cl a b
Rhine (SN m cl a b
sn forall (m :: Type -> Type) cl a b c.
(Clock m (Out cl), Time cl ~ Time (Out cl)) =>
SN m cl a b -> ClSF m (Out cl) b c -> SN m cl a c
>--^ ClSF m (Out cl) b c
clsf) cl
cl

-- | Precompose a 'Rhine' with a 'ClSF'.
(^->@) ::
  ( Clock m (In cl)
  , Time cl ~ Time (In cl)
  ) =>
  ClSF  m (In cl) a b   ->
  Rhine m     cl    b c ->
  Rhine m     cl  a   c
ClSF m (In cl) a b
clsf ^->@ :: forall (m :: Type -> Type) cl a b c.
(Clock m (In cl), Time cl ~ Time (In cl)) =>
ClSF m (In cl) a b -> Rhine m cl b c -> Rhine m cl a c
^->@ Rhine SN m cl b c
sn cl
cl = forall (m :: Type -> Type) cl a b.
SN m cl a b -> cl -> Rhine m cl a b
Rhine (ClSF m (In cl) a b
clsf forall (m :: Type -> Type) cl a b c.
(Clock m (In cl), Time cl ~ Time (In cl)) =>
ClSF m (In cl) a b -> SN m cl b c -> SN m cl a c
^--> SN m cl b c
sn) cl
cl
{- FOURMOLU_ENABLE -}