content: 
  -- |
  -- Module     : Simulation.Aivika.Ref.Base
  -- Copyright  : Copyright (c) 2009-2017, David Sorokin <david.sorokin@gmail.com>
  -- License    : BSD3
  -- Maintainer : David Sorokin <david.sorokin@gmail.com>
  -- Stability  : experimental
  -- Tested with: GHC 8.0.1
  --
  -- This module defines a light-weight and more fast version of an updatable reference
  -- that depends on the event queue but that doesn't supply with the signal notification.
  --
  module Simulation.Aivika.Ref.Base
         (Ref,
          newRef,
          readRef,
          writeRef,
          modifyRef) where
  
  import Data.IORef
  import Control.Monad
  import Control.Monad.Trans
  
  import Simulation.Aivika.Internal.Simulation
  import Simulation.Aivika.Internal.Event
  
  -- | 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.
  newtype Ref a = 
    Ref { refValue :: IORef a }
  
  -- | Create a new reference.
  newRef :: a -> Simulation (Ref a)
  newRef a =
    do x <- liftIO $ newIORef a
       return Ref { refValue = x }
       
  -- | Read the value of a reference.
  readRef :: Ref a -> Event a
  readRef r = Event $ \p -> readIORef (refValue r)
  
  -- | Write a new value into the reference.
  writeRef :: Ref a -> a -> Event ()
  writeRef r a = Event $ \p -> 
    a `seq` writeIORef (refValue r) a
  
  -- | Mutate the contents of the reference.
  modifyRef :: Ref a -> (a -> a) -> Event ()
  modifyRef r f = Event $ \p -> 
    do a <- readIORef (refValue r)
       let b = f a
       b `seq` writeIORef (refValue r) b
  