aivika-5.1: Simulation/Aivika/Composite.hs
{-# LANGUAGE MultiParamTypeClasses, RecursiveDo #-}
-- |
-- Module : Simulation.Aivika.Composite
-- 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
--
-- It defines the 'Composite' monad that allows constructing components which
-- can be then destroyed in case of need.
--
module Simulation.Aivika.Composite
(-- * Composite Monad
Composite,
CompositeLift(..),
runComposite,
runComposite_,
runCompositeInStartTime_,
runCompositeInStopTime_,
disposableComposite) where
import Data.Monoid
import Control.Exception
import Control.Monad
import Control.Monad.Trans
import Control.Monad.Fix
import Control.Applicative
import Simulation.Aivika.Parameter
import Simulation.Aivika.Simulation
import Simulation.Aivika.Dynamics
import Simulation.Aivika.Event
-- | It represents a composite which can be then destroyed in case of need.
newtype Composite a = Composite { runComposite :: DisposableEvent -> Event (a, DisposableEvent)
-- ^ Run the computation returning the result
-- and some 'DisposableEvent' that being applied
-- destroys the composite, for example, unsubscribes
-- from signals or cancels the processes.
--
}
-- | Like 'runComposite' but retains the composite parts during the simulation.
runComposite_ :: Composite a -> Event a
runComposite_ m =
do (a, _) <- runComposite m mempty
return a
-- | Like 'runComposite_' but runs the computation in the start time.
runCompositeInStartTime_ :: Composite a -> Simulation a
runCompositeInStartTime_ = runEventInStartTime . runComposite_
-- | Like 'runComposite_' but runs the computation in the stop time.
runCompositeInStopTime_ :: Composite a -> Simulation a
runCompositeInStopTime_ = runEventInStopTime . runComposite_
-- | When destroying the composite, the specified action will be applied.
disposableComposite :: DisposableEvent -> Composite ()
disposableComposite h = Composite $ \h0 -> return ((), h0 <> h)
instance Functor Composite where
fmap f (Composite m) =
Composite $ \h0 ->
do (a, h) <- m h0
return (f a, h)
instance Applicative Composite where
pure = return
(<*>) = ap
instance Monad Composite where
return a = Composite $ \h0 -> return (a, h0)
(Composite m) >>= k =
Composite $ \h0 ->
do (a, h) <- m h0
let Composite m' = k a
(b, h') <- m' h
return (b, h')
instance MonadIO Composite where
liftIO m =
Composite $ \h0 ->
do a <- liftIO m
return (a, h0)
instance MonadFix Composite where
mfix f =
Composite $ \h0 ->
do rec (a, h) <- runComposite (f a) h0
return (a, h)
instance ParameterLift Composite where
liftParameter m =
Composite $ \h0 ->
do a <- liftParameter m
return (a, h0)
instance SimulationLift Composite where
liftSimulation m =
Composite $ \h0 ->
do a <- liftSimulation m
return (a, h0)
instance DynamicsLift Composite where
liftDynamics m =
Composite $ \h0 ->
do a <- liftDynamics m
return (a, h0)
instance EventLift Composite where
liftEvent m =
Composite $ \h0 ->
do a <- liftEvent m
return (a, h0)
-- | A type class to lift the 'Composite' computation to other computations.
class CompositeLift m where
-- | Lift the specified 'Composite' computation to another computation.
liftComposite :: Composite a -> m a
instance CompositeLift Composite where
liftComposite = id