module Simulation.Aivika.Branch.Internal.BR
(BRParams(..),
BR(..),
invokeBR,
runBR,
newBRParams,
newRootBRParams,
branchLevel) where
import Data.IORef
import Data.Maybe
import Control.Applicative
import Control.Monad
import Control.Monad.Trans
import Control.Monad.Fix
import Control.Exception (throw, catch, finally)
import Simulation.Aivika.Trans.Exception
newtype BR m a = BR { unBR :: BRParams -> m a
}
data BRParams =
BRParams { brId :: !Int,
brIdGenerator :: IORef Int,
brLevel :: !Int,
brParent :: Maybe BRParams,
brUniqueRef :: IORef ()
}
instance Monad m => Monad (BR m) where
return = BR . const . return
(BR m) >>= k = BR $ \ps ->
m ps >>= \a ->
let m' = unBR (k a) in m' ps
instance Applicative m => Applicative (BR m) where
pure = BR . const . pure
(BR f) <*> (BR m) = BR $ \ps -> f ps <*> m ps
instance Functor m => Functor (BR m) where
fmap f (BR m) = BR $ fmap f . m
instance MonadIO m => MonadIO (BR m) where
liftIO = BR . const . liftIO
instance MonadTrans BR where
lift = BR . const
instance MonadFix m => MonadFix (BR m) where
mfix f =
BR $ \ps ->
do { rec { a <- invokeBR ps (f a) }; return a }
instance MonadException m => MonadException (BR m) where
catchComp (BR m) h = BR $ \ps ->
catchComp (m ps) (\e -> unBR (h e) ps)
finallyComp (BR m1) (BR m2) = BR $ \ps ->
finallyComp (m1 ps) (m2 ps)
throwComp e = BR $ \ps ->
throwComp e
invokeBR :: BRParams -> BR m a -> m a
invokeBR ps (BR m) = m ps
runBR :: MonadIO m => BR m a -> m a
runBR m =
do ps <- liftIO newRootBRParams
unBR m ps
newBRParams :: BRParams -> IO BRParams
newBRParams ps =
do id <- atomicModifyIORef (brIdGenerator ps) $ \a ->
let b = a + 1 in b `seq` (b, b)
let level = 1 + brLevel ps
uniqueRef <- newIORef ()
return BRParams { brId = id,
brIdGenerator = brIdGenerator ps,
brLevel = level `seq` level,
brParent = Just ps,
brUniqueRef = uniqueRef }
newRootBRParams :: IO BRParams
newRootBRParams =
do genId <- newIORef 0
uniqueRef <- newIORef ()
return BRParams { brId = 0,
brIdGenerator = genId,
brLevel = 0,
brParent = Nothing,
brUniqueRef = uniqueRef
}
branchLevel :: Monad m => BR m Int
branchLevel = BR $ \ps -> return (brLevel ps)