-- |
-- Module     : Simulation.Aivika.Trans.Channel
-- Copyright  : Copyright (c) 2009-2017, David Sorokin <david.sorokin@gmail.com>
-- License    : BSD3
-- Maintainer : David Sorokin <david.sorokin@gmail.com>
-- Stability  : experimental
-- Tested with: GHC 8.0.1
--
-- The module defines a channel that transforms one 'Signal' to another
-- within the 'Composite' computation.
--
module Simulation.Aivika.Trans.Channel
       (-- * Channel Computation
        Channel(..),
        -- * Delay Channel
        delayChannel,
        delayChannelM,
        -- * Sinking Signal
        sinkSignal,
        -- * Debugging
        traceChannel) where

import qualified Control.Category as C
import Control.Monad

import Simulation.Aivika.Trans.DES
import Simulation.Aivika.Trans.Simulation
import Simulation.Aivika.Trans.Dynamics
import Simulation.Aivika.Trans.Event
import Simulation.Aivika.Trans.Signal
import Simulation.Aivika.Trans.Composite

-- | It allows representing a signal transformation.
newtype Channel m a b =
  Channel { forall (m :: * -> *) a b.
Channel m a b -> Signal m a -> Composite m (Signal m b)
runChannel :: Signal m a -> Composite m (Signal m b)
            -- ^ Run the channel transform.
          }

instance MonadDES m => C.Category (Channel m) where

  {-# INLINE id #-}
  id :: forall a. Channel m a a
id = forall (m :: * -> *) a b.
(Signal m a -> Composite m (Signal m b)) -> Channel m a b
Channel forall (m :: * -> *) a. Monad m => a -> m a
return

  {-# INLINE (.) #-}
  (Channel Signal m b -> Composite m (Signal m c)
g) . :: forall b c a. Channel m b c -> Channel m a b -> Channel m a c
. (Channel Signal m a -> Composite m (Signal m b)
f) =
    forall (m :: * -> *) a b.
(Signal m a -> Composite m (Signal m b)) -> Channel m a b
Channel forall a b. (a -> b) -> a -> b
$ \Signal m a
a -> Signal m a -> Composite m (Signal m b)
f Signal m a
a forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Signal m b -> Composite m (Signal m c)
g

-- | Return a delayed signal.
--
-- This is actually the 'delaySignal' function wrapped in the 'Channel' type. 
delayChannel :: MonadDES m
                => Double           -- ^ the delay
                -> Channel m a a    -- ^ the delay channel
{-# INLINABLE delayChannel #-}
delayChannel :: forall (m :: * -> *) a. MonadDES m => Double -> Channel m a a
delayChannel Double
delay =
  forall (m :: * -> *) a b.
(Signal m a -> Composite m (Signal m b)) -> Channel m a b
Channel forall a b. (a -> b) -> a -> b
$ \Signal m a
a -> forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ forall (m :: * -> *) a.
MonadDES m =>
Double -> Signal m a -> Signal m a
delaySignal Double
delay Signal m a
a

-- | Like 'delayChannel', but it re-computes the delay each time.
--
-- This is actually the 'delaySignalM' function wrapped in the 'Channel' type. 
delayChannelM :: MonadDES m
                 => Event m Double    -- ^ the delay
                 -> Channel m a a     -- ^ the delay channel
{-# INLINABLE delayChannelM #-}
delayChannelM :: forall (m :: * -> *) a.
MonadDES m =>
Event m Double -> Channel m a a
delayChannelM Event m Double
delay =
  forall (m :: * -> *) a b.
(Signal m a -> Composite m (Signal m b)) -> Channel m a b
Channel forall a b. (a -> b) -> a -> b
$ \Signal m a
a -> forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ forall (m :: * -> *) a.
MonadDES m =>
Event m Double -> Signal m a -> Signal m a
delaySignalM Event m Double
delay Signal m a
a

-- | Sink the signal. It returns a computation that subscribes to
-- the signal and then ignores the received data. The resulting
-- computation can be a moving force to simulate the whole system of
-- the interconnected signals and channels.
sinkSignal :: MonadDES m => Signal m a -> Composite m ()
{-# INLINABLE sinkSignal #-}
sinkSignal :: forall (m :: * -> *) a. MonadDES m => Signal m a -> Composite m ()
sinkSignal Signal m a
a =
  do DisposableEvent m
h <- forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
EventLift t m =>
Event m a -> t m a
liftEvent forall a b. (a -> b) -> a -> b
$
          forall (m :: * -> *) a.
Signal m a -> (a -> Event m ()) -> Event m (DisposableEvent m)
handleSignal Signal m a
a forall a b. (a -> b) -> a -> b
$
          forall a b. a -> b -> a
const forall a b. (a -> b) -> a -> b
$ forall (m :: * -> *) a. Monad m => a -> m a
return ()
     forall (m :: * -> *).
Monad m =>
DisposableEvent m -> Composite m ()
disposableComposite DisposableEvent m
h
                                 
-- | Show the debug message with the current simulation time,
-- when emitting the output signal.
traceChannel :: MonadDES m => String -> Channel m a b -> Channel m a b
{-# INLINABLE traceChannel #-}
traceChannel :: forall (m :: * -> *) a b.
MonadDES m =>
String -> Channel m a b -> Channel m a b
traceChannel String
message (Channel Signal m a -> Composite m (Signal m b)
f) =
  forall (m :: * -> *) a b.
(Signal m a -> Composite m (Signal m b)) -> Channel m a b
Channel forall a b. (a -> b) -> a -> b
$ \Signal m a
a ->
  do Signal m b
b <- Signal m a -> Composite m (Signal m b)
f Signal m a
a
     forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$
       forall (m :: * -> *) a.
MonadDES m =>
String -> Signal m a -> Signal m a
traceSignal String
message Signal m b
b