module Simulation.Aivika.Trans.Internal.Event
(
Event(..),
EventLift(..),
EventProcessing(..),
invokeEvent,
runEventInStartTime,
runEventInStopTime,
EventQueueing(..),
enqueueEventWithCancellation,
enqueueEventWithStartTime,
enqueueEventWithStopTime,
enqueueEventWithTimes,
enqueueEventWithPoints,
enqueueEventWithIntegTimes,
yieldEvent,
EventCancellation,
cancelEvent,
eventCancelled,
eventFinished,
catchEvent,
finallyEvent,
throwEvent,
memoEvent,
memoEventInTime,
DisposableEvent(..),
retryEvent,
EventIOQueueing(..),
enqueueEventIOWithStartTime,
enqueueEventIOWithStopTime,
enqueueEventIOWithTimes,
enqueueEventIOWithPoints,
enqueueEventIOWithIntegTimes,
traceEvent) where
import Data.Monoid
import Control.Exception
import Control.Monad
import Control.Monad.Trans
import Control.Monad.Fix
import Control.Applicative
import Debug.Trace (trace)
import Simulation.Aivika.Trans.Exception
import Simulation.Aivika.Trans.Ref.Base
import Simulation.Aivika.Trans.Comp
import Simulation.Aivika.Trans.DES
import Simulation.Aivika.Trans.Internal.Types
import Simulation.Aivika.Trans.Internal.Specs
import Simulation.Aivika.Trans.Internal.Parameter
import Simulation.Aivika.Trans.Internal.Simulation
import Simulation.Aivika.Trans.Internal.Dynamics
instance Monad m => Monad (Event m) where
return a = Event $ \p -> return a
(Event m) >>= k =
Event $ \p ->
do a <- m p
let Event m' = k a
m' p
instance Functor m => Functor (Event m) where
fmap f (Event x) = Event $ \p -> fmap f $ x p
instance Applicative m => Applicative (Event m) where
pure = Event . const . pure
(Event x) <*> (Event y) = Event $ \p -> x p <*> y p
instance MonadTrans Event where
lift = Event . const
instance MonadIO m => MonadIO (Event m) where
liftIO = Event . const . liftIO
instance Monad m => MonadCompTrans Event m where
liftComp = Event . const
class EventLift t m where
liftEvent :: Event m a -> t m a
instance Monad m => EventLift Event m where
liftEvent = id
instance Monad m => DynamicsLift Event m where
liftDynamics (Dynamics x) = Event x
instance Monad m => SimulationLift Event m where
liftSimulation (Simulation x) = Event $ x . pointRun
instance Monad m => ParameterLift Event m where
liftParameter (Parameter x) = Event $ x . pointRun
catchEvent :: (MonadException m, Exception e) => Event m a -> (e -> Event m a) -> Event m a
catchEvent (Event m) h =
Event $ \p ->
catchComp (m p) $ \e ->
let Event m' = h e in m' p
finallyEvent :: MonadException m => Event m a -> Event m b -> Event m a
finallyEvent (Event m) (Event m') =
Event $ \p ->
finallyComp (m p) (m' p)
throwEvent :: (MonadException m, Exception e) => e -> Event m a
throwEvent e =
Event $ \p ->
throwComp e
instance MonadFix m => MonadFix (Event m) where
mfix f =
Event $ \p ->
do { rec { a <- invokeEvent p (f a) }; return a }
runEventInStartTime :: MonadDES m => Event m a -> Simulation m a
runEventInStartTime = runDynamicsInStartTime . runEvent
runEventInStopTime :: MonadDES m => Event m a -> Simulation m a
runEventInStopTime = runDynamicsInStopTime . runEvent
enqueueEventWithTimes :: MonadDES m => [Double] -> Event m () -> Event m ()
enqueueEventWithTimes ts e = loop ts
where loop [] = return ()
loop (t : ts) = enqueueEvent t $ e >> loop ts
enqueueEventWithPoints :: MonadDES m => [Point m] -> Event m () -> Event m ()
enqueueEventWithPoints xs (Event e) = loop xs
where loop [] = return ()
loop (x : xs) = enqueueEvent (pointTime x) $
Event $ \p ->
do e x
invokeEvent p $ loop xs
enqueueEventWithIntegTimes :: MonadDES m => Event m () -> Event m ()
enqueueEventWithIntegTimes e =
Event $ \p ->
let points = integPointsStartingFrom p
in invokeEvent p $ enqueueEventWithPoints points e
enqueueEventWithStartTime :: MonadDES m => Event m () -> Event m ()
enqueueEventWithStartTime e =
Event $ \p ->
let p0 = integStartPoint $ pointRun p
in invokeEvent p $ enqueueEventWithPoints [p0] e
enqueueEventWithStopTime :: MonadDES m => Event m () -> Event m ()
enqueueEventWithStopTime e =
Event $ \p ->
let p0 = simulationStopPoint $ pointRun p
in invokeEvent p $ enqueueEventWithPoints [p0] e
data EventCancellation m =
EventCancellation { cancelEvent :: Event m (),
eventCancelled :: Event m Bool,
eventFinished :: Event m Bool
}
enqueueEventWithCancellation :: MonadDES m => Double -> Event m () -> Event m (EventCancellation m)
enqueueEventWithCancellation t e =
Event $ \p ->
do let r = pointRun p
cancelledRef <- invokeSimulation r $ newRef False
cancellableRef <- invokeSimulation r $ newRef True
finishedRef <- invokeSimulation r $ newRef False
let cancel =
Event $ \p ->
do x <- invokeEvent p $ readRef cancellableRef
when x $
invokeEvent p $ writeRef cancelledRef True
cancelled =
readRef cancelledRef
finished =
readRef finishedRef
invokeEvent p $
enqueueEvent t $
Event $ \p ->
do invokeEvent p $ writeRef cancellableRef False
x <- invokeEvent p $ readRef cancelledRef
unless x $
do invokeEvent p e
invokeEvent p $ writeRef finishedRef True
return EventCancellation { cancelEvent = cancel,
eventCancelled = cancelled,
eventFinished = finished }
memoEvent :: MonadDES m => Event m a -> Simulation m (Event m a)
memoEvent m =
Simulation $ \r ->
do ref <- invokeSimulation r $ newRef Nothing
return $ Event $ \p ->
do x <- invokeEvent p $ readRef ref
case x of
Just v -> return v
Nothing ->
do v <- invokeEvent p m
invokeEvent p $ writeRef ref (Just v)
return v
memoEventInTime :: MonadDES m => Event m a -> Simulation m (Event m a)
memoEventInTime m =
Simulation $ \r ->
do ref <- invokeSimulation r $ newRef Nothing
return $ Event $ \p ->
do x <- invokeEvent p $ readRef ref
case x of
Just (t, v) | t == pointTime p ->
return v
_ ->
do v <- invokeEvent p m
invokeEvent p $ writeRef ref (Just (pointTime p, v))
return v
yieldEvent :: MonadDES m => Event m () -> Event m ()
yieldEvent m =
Event $ \p ->
invokeEvent p $
enqueueEvent (pointTime p) m
newtype DisposableEvent m =
DisposableEvent { disposeEvent :: Event m ()
}
instance Monad m => Monoid (DisposableEvent m) where
mempty = DisposableEvent $ return ()
mappend (DisposableEvent x) (DisposableEvent y) = DisposableEvent $ x >> y
retryEvent :: MonadException m => String -> Event m a
retryEvent message = throwEvent $ SimulationRetry message
traceEvent :: MonadDES m => String -> Event m a -> Event m a
traceEvent message m =
Event $ \p ->
trace ("t = " ++ show (pointTime p) ++ ": " ++ message) $
invokeEvent p m
class (EventQueueing m, MonadIO (Event m)) => EventIOQueueing m where
enqueueEventIO :: Double -> Event m () -> Event m ()
enqueueEventIOWithTimes :: (MonadDES m, EventIOQueueing m) => [Double] -> Event m () -> Event m ()
enqueueEventIOWithTimes ts e = loop ts
where loop [] = return ()
loop (t : ts) = enqueueEventIO t $ e >> loop ts
enqueueEventIOWithPoints :: (MonadDES m, EventIOQueueing m) => [Point m] -> Event m () -> Event m ()
enqueueEventIOWithPoints xs (Event e) = loop xs
where loop [] = return ()
loop (x : xs) = enqueueEventIO (pointTime x) $
Event $ \p ->
do e x
invokeEvent p $ loop xs
enqueueEventIOWithIntegTimes :: (MonadDES m, EventIOQueueing m) => Event m () -> Event m ()
enqueueEventIOWithIntegTimes e =
Event $ \p ->
let points = integPointsStartingFrom p
in invokeEvent p $ enqueueEventIOWithPoints points e
enqueueEventIOWithStartTime :: (MonadDES m, EventIOQueueing m) => Event m () -> Event m ()
enqueueEventIOWithStartTime e =
Event $ \p ->
let p0 = integStartPoint $ pointRun p
in invokeEvent p $ enqueueEventIOWithPoints [p0] e
enqueueEventIOWithStopTime :: (MonadDES m, EventIOQueueing m) => Event m () -> Event m ()
enqueueEventIOWithStopTime e =
Event $ \p ->
let p0 = simulationStopPoint $ pointRun p
in invokeEvent p $ enqueueEventIOWithPoints [p0] e