{-# LANGUAGE MultiParamTypeClasses, FlexibleInstances, FlexibleContexts, UndecidableInstances #-} -- | -- Module : Simulation.Aivika.Trans.Ref -- Copyright : Copyright (c) 2009-2017, David Sorokin -- License : BSD3 -- Maintainer : David Sorokin -- Stability : experimental -- Tested with: GHC 8.0.1 -- -- This module defines an updatable reference that depends on the event queue. -- module Simulation.Aivika.Trans.Ref (Ref, refChanged, refChanged_, newRef, newRef0, readRef, writeRef, modifyRef) where import Data.IORef import Control.Monad import Control.Monad.Trans import Simulation.Aivika.Trans.Internal.Simulation import Simulation.Aivika.Trans.Internal.Event import Simulation.Aivika.Trans.Signal import qualified Simulation.Aivika.Trans.Ref.Base as B import Simulation.Aivika.Trans.DES import Simulation.Aivika.Trans.Observable -- | The 'Ref' type represents a mutable variable similar to the 'IORef' variable -- but only dependent on the event queue, which allows synchronizing the reference -- with the model explicitly through the 'Event' monad. data Ref m a = Ref { refValue :: B.Ref m a, refChangedSource :: SignalSource m a } -- | Create a new reference. newRef :: MonadDES m => a -> Simulation m (Ref m a) {-# INLINABLE newRef #-} newRef a = Simulation $ \r -> do x <- invokeSimulation r $ B.newRef a s <- invokeSimulation r newSignalSource return Ref { refValue = x, refChangedSource = s } -- | Create a new reference within more low level computation than 'Simulation'. newRef0 :: (MonadDES m, B.MonadRef0 m) => a -> m (Ref m a) {-# INLINABLE newRef0 #-} newRef0 a = do x <- B.newRef0 a s <- newSignalSource0 return Ref { refValue = x, refChangedSource = s } -- | Read the value of a reference. readRef :: MonadDES m => Ref m a -> Event m a {-# INLINE readRef #-} readRef r = B.readRef (refValue r) -- | Write a new value into the reference. writeRef :: MonadDES m => Ref m a -> a -> Event m () {-# INLINABLE writeRef #-} writeRef r a = Event $ \p -> do a `seq` invokeEvent p $ B.writeRef (refValue r) a invokeEvent p $ triggerSignal (refChangedSource r) a -- | Mutate the contents of the reference. modifyRef :: MonadDES m => Ref m a -> (a -> a) -> Event m () {-# INLINABLE modifyRef #-} modifyRef r f = Event $ \p -> do a <- invokeEvent p $ B.readRef (refValue r) let b = f a b `seq` invokeEvent p $ B.writeRef (refValue r) b invokeEvent p $ triggerSignal (refChangedSource r) b -- | Return a signal that notifies about every change of the reference state. refChanged :: Ref m a -> Signal m a {-# INLINE refChanged #-} refChanged r = publishSignal (refChangedSource r) -- | Return a signal that notifies about every change of the reference state. refChanged_ :: MonadDES m => Ref m a -> Signal m () {-# INLINABLE refChanged_ #-} refChanged_ r = mapSignal (const ()) $ refChanged r instance MonadDES m => Eq (Ref m a) where {-# INLINE (==) #-} r1 == r2 = (refValue r1) == (refValue r2) instance (MonadDES m, Observable (B.Ref m) (t m)) => Observable (Ref m) (t m) where {-# INLINE readObservable #-} readObservable r = readObservable (refValue r)