------------------------------------------------------------------------ -- | -- Module : ALife.Creatur.Counter -- Copyright : (c) Amy de Buitléir 2012-2013 -- License : BSD-style -- Maintainer : amy@nualeargais.ie -- Stability : experimental -- Portability : portable -- -- A simple counter which persists between runs. -- ------------------------------------------------------------------------ module ALife.Creatur.Counter ( Counter(..), PersistentCounter, mkPersistentCounter ) where import ALife.Creatur.Clock (Clock, currentTime, incTime) import Control.Monad (unless) import Control.Monad.IO.Class (liftIO) import Control.Monad.State (StateT, get, gets, modify, put) import System.Directory (doesFileExist) class Counter c where current :: StateT c IO Int increment :: StateT c IO () data PersistentCounter = PersistentCounter { initialised :: Bool, time :: Int, filename :: FilePath } deriving Show -- | Creates a counter that will store its value in the specified file. mkPersistentCounter :: FilePath -> PersistentCounter mkPersistentCounter = PersistentCounter False (-1) instance Counter PersistentCounter where current = do initIfNeeded gets time increment = do t <- current let t' = t + 1 f <- gets filename modify (\c -> c { time=t' }) liftIO $ writeFile f $ show t' initIfNeeded :: StateT PersistentCounter IO () initIfNeeded = do isInitialised <- gets initialised unless isInitialised $ do counter <- get counter' <- liftIO $ initialise counter put counter' initialise :: PersistentCounter -> IO PersistentCounter initialise counter = do let f = filename counter fExists <- doesFileExist f if fExists then do s <- readFile f return $ counter { initialised=True, time=read s } else return $ counter { initialised=True, time=0 } instance Clock PersistentCounter where currentTime = current incTime = increment