{-# LANGUAGE RecursiveDo, ExistentialQuantification, DeriveDataTypeable, RankNTypes #-}
module Simulation.Aivika.Internal.Simulation
(
Simulation(..),
SimulationLift(..),
invokeSimulation,
runSimulation,
runSimulations,
runSimulationByIndex,
catchSimulation,
finallySimulation,
throwSimulation,
simulationEventQueue,
memoSimulation,
SimulationException(..),
SimulationAbort(..),
SimulationRetry(..)) where
import Control.Exception
import Control.Monad
import Control.Monad.Trans
import Control.Monad.Fix
import qualified Control.Monad.Catch as MC
import Control.Applicative
import Data.IORef
import Data.Typeable
import Simulation.Aivika.Generator
import Simulation.Aivika.Internal.Specs
import Simulation.Aivika.Internal.Parameter
newtype Simulation a = Simulation (Run -> IO a)
instance Monad Simulation where
return = returnS
m >>= k = bindS m k
returnS :: a -> Simulation a
{-# INLINE returnS #-}
returnS a = Simulation (\r -> return a)
bindS :: Simulation a -> (a -> Simulation b) -> Simulation b
{-# INLINE bindS #-}
bindS (Simulation m) k =
Simulation $ \r ->
do a <- m r
let Simulation m' = k a
m' r
runSimulation :: Simulation a -> Specs -> IO a
runSimulation (Simulation m) sc =
do q <- newEventQueue sc
g <- newGenerator $ spcGeneratorType sc
m Run { runSpecs = sc,
runIndex = 1,
runCount = 1,
runEventQueue = q,
runGenerator = g }
runSimulationByIndex :: Simulation a
-> Specs
-> Int
-> Int
-> IO a
runSimulationByIndex (Simulation m) sc runs index =
do q <- newEventQueue sc
g <- newGenerator $ spcGeneratorType sc
m Run { runSpecs = sc,
runIndex = index,
runCount = runs,
runEventQueue = q,
runGenerator = g }
runSimulations :: Simulation a -> Specs -> Int -> [IO a]
runSimulations (Simulation m) sc runs = map f [1 .. runs]
where f i = do q <- newEventQueue sc
g <- newGenerator $ spcGeneratorType sc
m Run { runSpecs = sc,
runIndex = i,
runCount = runs,
runEventQueue = q,
runGenerator = g }
simulationEventQueue :: Simulation EventQueue
simulationEventQueue = Simulation $ return . runEventQueue
instance Functor Simulation where
fmap = liftMS
instance Applicative Simulation where
pure = return
(<*>) = ap
liftMS :: (a -> b) -> Simulation a -> Simulation b
{-# INLINE liftMS #-}
liftMS f (Simulation x) =
Simulation $ \r -> do { a <- x r; return $ f a }
instance MonadIO Simulation where
liftIO m = Simulation $ const m
class SimulationLift m where
liftSimulation :: Simulation a -> m a
instance SimulationLift Simulation where
liftSimulation = id
instance ParameterLift Simulation where
liftParameter = liftPS
liftPS :: Parameter a -> Simulation a
{-# INLINE liftPS #-}
liftPS (Parameter x) =
Simulation x
catchSimulation :: Exception e => Simulation a -> (e -> Simulation a) -> Simulation a
catchSimulation (Simulation m) h =
Simulation $ \r ->
catch (m r) $ \e ->
let Simulation m' = h e in m' r
finallySimulation :: Simulation a -> Simulation b -> Simulation a
finallySimulation (Simulation m) (Simulation m') =
Simulation $ \r ->
finally (m r) (m' r)
throwSimulation :: Exception e => e -> Simulation a
throwSimulation = throw
maskSimulation :: ((forall a. Simulation a -> Simulation a) -> Simulation b) -> Simulation b
maskSimulation a =
Simulation $ \r ->
MC.mask $ \u ->
invokeSimulation r (a $ q u)
where q u (Simulation b) = Simulation (u . b)
uninterruptibleMaskSimulation :: ((forall a. Simulation a -> Simulation a) -> Simulation b) -> Simulation b
uninterruptibleMaskSimulation a =
Simulation $ \r ->
MC.uninterruptibleMask $ \u ->
invokeSimulation r (a $ q u)
where q u (Simulation b) = Simulation (u . b)
generalBracketSimulation :: Simulation a
-> (a -> MC.ExitCase b -> Simulation c)
-> (a -> Simulation b)
-> Simulation (b, c)
generalBracketSimulation acquire release use =
Simulation $ \r -> do
MC.generalBracket
(invokeSimulation r acquire)
(\resource e -> invokeSimulation r $ release resource e)
(\resource -> invokeSimulation r $ use resource)
invokeSimulation :: Run -> Simulation a -> IO a
{-# INLINE invokeSimulation #-}
invokeSimulation r (Simulation m) = m r
instance MonadFix Simulation where
mfix f =
Simulation $ \r ->
do { rec { a <- invokeSimulation r (f a) }; return a }
instance MC.MonadThrow Simulation where
throwM = throwSimulation
instance MC.MonadCatch Simulation where
catch = catchSimulation
instance MC.MonadMask Simulation where
mask = maskSimulation
uninterruptibleMask = uninterruptibleMaskSimulation
generalBracket = generalBracketSimulation
memoSimulation :: Simulation a -> Simulation (Simulation a)
memoSimulation m =
do ref <- liftIO $ newIORef Nothing
return $ Simulation $ \r ->
do x <- readIORef ref
case x of
Just v -> return v
Nothing ->
do v <- invokeSimulation r m
writeIORef ref (Just v)
return v
data SimulationException = forall e . Exception e => SimulationException e
deriving Typeable
instance Show SimulationException where
show (SimulationException e) = show e
instance Exception SimulationException
data SimulationAbort = SimulationAbort String
deriving (Show, Typeable)
data SimulationRetry = SimulationRetry String
deriving (Show, Typeable)
instance Exception SimulationAbort where
toException = toException . SimulationException
fromException x = do { SimulationException a <- fromException x; cast a }
instance Exception SimulationRetry where
toException = toException . SimulationException
fromException x = do { SimulationException a <- fromException x; cast a }