packages feed

creatur-2.0.10: src/ALife/Creatur/Counter.hs

------------------------------------------------------------------------
-- |
-- Module      :  ALife.Creatur.Tools.Logger
-- 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.
--
------------------------------------------------------------------------
{-# LANGUAGE UnicodeSyntax #-}
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