-- |
-- Module     : Simulation.Aivika.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.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.Simulation
import Simulation.Aivika.Dynamics
import Simulation.Aivika.Event
import Simulation.Aivika.Signal
import Simulation.Aivika.Composite

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

instance C.Category Channel where

  id :: forall a. Channel a a
id = (Signal a -> Composite (Signal a)) -> Channel a a
forall a b. (Signal a -> Composite (Signal b)) -> Channel a b
Channel Signal a -> Composite (Signal a)
forall a. a -> Composite a
forall (m :: * -> *) a. Monad m => a -> m a
return
  
  (Channel Signal b -> Composite (Signal c)
g) . :: forall b c a. Channel b c -> Channel a b -> Channel a c
. (Channel Signal a -> Composite (Signal b)
f) =
    (Signal a -> Composite (Signal c)) -> Channel a c
forall a b. (Signal a -> Composite (Signal b)) -> Channel a b
Channel ((Signal a -> Composite (Signal c)) -> Channel a c)
-> (Signal a -> Composite (Signal c)) -> Channel a c
forall a b. (a -> b) -> a -> b
$ \Signal a
a -> Signal a -> Composite (Signal b)
f Signal a
a Composite (Signal b)
-> (Signal b -> Composite (Signal c)) -> Composite (Signal c)
forall a b. Composite a -> (a -> Composite b) -> Composite b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Signal b -> Composite (Signal c)
g

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

-- | Like 'delayChannel', but it re-computes the delay each time.
--
-- This is actually the 'delaySignalM' function wrapped in the 'Channel' type. 
delayChannelM :: Event Double     -- ^ the delay
                 -> Channel a a    -- ^ the delay channel
delayChannelM :: forall a. Event Double -> Channel a a
delayChannelM Event Double
delay =
  (Signal a -> Composite (Signal a)) -> Channel a a
forall a b. (Signal a -> Composite (Signal b)) -> Channel a b
Channel ((Signal a -> Composite (Signal a)) -> Channel a a)
-> (Signal a -> Composite (Signal a)) -> Channel a a
forall a b. (a -> b) -> a -> b
$ \Signal a
a -> Signal a -> Composite (Signal a)
forall a. a -> Composite a
forall (m :: * -> *) a. Monad m => a -> m a
return (Signal a -> Composite (Signal a))
-> Signal a -> Composite (Signal a)
forall a b. (a -> b) -> a -> b
$ Event Double -> Signal a -> Signal a
forall a. Event Double -> Signal a -> Signal a
delaySignalM Event Double
delay Signal 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 :: Signal a -> Composite ()
sinkSignal :: forall a. Signal a -> Composite ()
sinkSignal Signal a
a =
  do DisposableEvent
h <- Event DisposableEvent -> Composite DisposableEvent
forall a. Event a -> Composite a
forall (m :: * -> *) a. EventLift m => Event a -> m a
liftEvent (Event DisposableEvent -> Composite DisposableEvent)
-> Event DisposableEvent -> Composite DisposableEvent
forall a b. (a -> b) -> a -> b
$
          Signal a -> (a -> Event ()) -> Event DisposableEvent
forall a. Signal a -> (a -> Event ()) -> Event DisposableEvent
handleSignal Signal a
a ((a -> Event ()) -> Event DisposableEvent)
-> (a -> Event ()) -> Event DisposableEvent
forall a b. (a -> b) -> a -> b
$
          Event () -> a -> Event ()
forall a b. a -> b -> a
const (Event () -> a -> Event ()) -> Event () -> a -> Event ()
forall a b. (a -> b) -> a -> b
$ () -> Event ()
forall a. a -> Event a
forall (m :: * -> *) a. Monad m => a -> m a
return ()
     DisposableEvent -> Composite ()
disposableComposite DisposableEvent
h
                                 
-- | Show the debug message with the current simulation time,
-- when emitting the output signal.
traceChannel :: String -> Channel a b -> Channel a b
traceChannel :: forall a b. String -> Channel a b -> Channel a b
traceChannel String
message (Channel Signal a -> Composite (Signal b)
f) =
  (Signal a -> Composite (Signal b)) -> Channel a b
forall a b. (Signal a -> Composite (Signal b)) -> Channel a b
Channel ((Signal a -> Composite (Signal b)) -> Channel a b)
-> (Signal a -> Composite (Signal b)) -> Channel a b
forall a b. (a -> b) -> a -> b
$ \Signal a
a ->
  do Signal b
b <- Signal a -> Composite (Signal b)
f Signal a
a
     Signal b -> Composite (Signal b)
forall a. a -> Composite a
forall (m :: * -> *) a. Monad m => a -> m a
return (Signal b -> Composite (Signal b))
-> Signal b -> Composite (Signal b)
forall a b. (a -> b) -> a -> b
$
       String -> Signal b -> Signal b
forall a. String -> Signal a -> Signal a
traceSignal String
message Signal b
b