{-# LANGUAGE RecursiveDo #-}
module Simulation.Aivika.Trans.Transform
(
Transform(..),
delayTransform,
timeTransform,
integTransform,
integTransformEither,
sumTransform,
sumTransformEither) where
import qualified Control.Category as C
import Control.Arrow
import Control.Monad
import Control.Monad.Fix
import Simulation.Aivika.Trans.Simulation
import Simulation.Aivika.Trans.Dynamics
import qualified Simulation.Aivika.Trans.Dynamics.Memo as M
import qualified Simulation.Aivika.Trans.Dynamics.Memo.Unboxed as MU
import Simulation.Aivika.Trans.SystemDynamics
import Simulation.Aivika.Trans.SD
newtype Transform m a b =
Transform { runTransform :: Dynamics m a -> Simulation m (Dynamics m b)
}
instance Monad m => C.Category (Transform m) where
{-# INLINE id #-}
id = Transform return
{-# INLINE (.) #-}
(Transform g) . (Transform f) =
Transform $ \a -> f a >>= g
instance MonadSD m => Arrow (Transform m) where
{-# INLINE arr #-}
arr f = Transform $ return . fmap f
{-# INLINABLE first #-}
first (Transform f) =
Transform $ \bd ->
do (b, d) <- M.unzip0Dynamics bd
c <- f b
return $ liftM2 (,) c d
{-# INLINABLE second #-}
second (Transform f) =
Transform $ \db ->
do (d, b) <- M.unzip0Dynamics db
c <- f b
return $ liftM2 (,) d c
{-# INLINABLE (***) #-}
(Transform f) *** (Transform g) =
Transform $ \bb' ->
do (b, b') <- M.unzip0Dynamics bb'
c <- f b
c' <- g b'
return $ liftM2 (,) c c'
{-# INLINABLE (&&&) #-}
(Transform f) &&& (Transform g) =
Transform $ \b ->
do c <- f b
c' <- g b
return $ liftM2 (,) c c'
timeTransform :: Monad m => Transform m a Double
{-# INLINE timeTransform #-}
timeTransform = Transform $ const $ return time
delayTransform :: MonadSD m
=> Dynamics m Double
-> Dynamics m a
-> Transform m a a
{-# INLINE delayTransform #-}
delayTransform lagTime init =
Transform $ \a -> delayI a lagTime init
integTransform :: (MonadSD m, MonadFix m)
=> Dynamics m Double
-> Transform m Double Double
{-# INLINE integTransform #-}
integTransform init = Transform $ \diff -> integ diff init
integTransformEither :: (MonadSD m, MonadFix m)
=> Dynamics m Double
-> Transform m (Either Double Double) Double
{-# INLINE integTransformEither #-}
integTransformEither init = Transform $ \diff -> integEither diff init
sumTransform :: (MonadSD m, MonadFix m, Num a, MU.MonadMemo m a)
=> Dynamics m a
-> Transform m a a
{-# INLINE sumTransform #-}
sumTransform init = Transform $ \diff -> diffsum diff init
sumTransformEither :: (MonadSD m, MonadFix m, Num a, MU.MonadMemo m a)
=> Dynamics m a
-> Transform m (Either a a) a
{-# INLINE sumTransformEither #-}
sumTransformEither init = Transform $ \diff -> diffsumEither diff init