{-# LANGUAGE MultiParamTypeClasses, RecursiveDo #-} -- | -- Module : Simulation.Aivika.Composite -- Copyright : Copyright (c) 2009-2017, David Sorokin -- License : BSD3 -- Maintainer : David Sorokin -- 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