packages feed

creatur 5.4.0 → 5.4.1

raw patch · 5 files changed

+204/−80 lines, 5 filesPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

API changes (from Hackage documentation)

- ALife.Creatur.Logger: data SimpleRotatingLogger
- ALife.Creatur.Logger: instance Eq SimpleRotatingLogger
- ALife.Creatur.Logger: instance Logger SimpleRotatingLogger
- ALife.Creatur.Logger: instance Show SimpleRotatingLogger
- ALife.Creatur.Logger: mkSimpleRotatingLogger :: FilePath -> String -> Int -> SimpleRotatingLogger
+ ALife.Creatur.Logger: timestamp :: IO String
+ ALife.Creatur.Logger.SimpleLogger: data SimpleLogger
+ ALife.Creatur.Logger.SimpleLogger: instance Eq SimpleLogger
+ ALife.Creatur.Logger.SimpleLogger: instance Logger SimpleLogger
+ ALife.Creatur.Logger.SimpleLogger: instance Show SimpleLogger
+ ALife.Creatur.Logger.SimpleLogger: mkSimpleLogger :: FilePath -> SimpleLogger
+ ALife.Creatur.Logger.SimpleRotatingLogger: class Logger l
+ ALife.Creatur.Logger.SimpleRotatingLogger: data SimpleRotatingLogger
+ ALife.Creatur.Logger.SimpleRotatingLogger: instance Eq SimpleRotatingLogger
+ ALife.Creatur.Logger.SimpleRotatingLogger: instance Logger SimpleRotatingLogger
+ ALife.Creatur.Logger.SimpleRotatingLogger: instance Show SimpleRotatingLogger
+ ALife.Creatur.Logger.SimpleRotatingLogger: mkSimpleRotatingLogger :: FilePath -> String -> Int -> SimpleRotatingLogger
+ ALife.Creatur.Logger.SimpleRotatingLogger: writeToLog :: Logger l => String -> StateT l IO ()
- ALife.Creatur.Universe: mkCachedUniverse :: String -> FilePath -> Int -> Int -> CachedUniverse a
+ ALife.Creatur.Universe: mkCachedUniverse :: String -> FilePath -> Int -> CachedUniverse a
- ALife.Creatur.Universe: mkSimpleUniverse :: String -> FilePath -> Int -> SimpleUniverse a
+ ALife.Creatur.Universe: mkSimpleUniverse :: String -> FilePath -> SimpleUniverse a

Files

creatur.cabal view
@@ -1,5 +1,5 @@ Name:              creatur-Version:           5.4.0+Version:           5.4.1 Stability:         experimental Synopsis:          Framework for artificial life experiments. Description:       A software framework for automating experiments@@ -36,7 +36,7 @@ source-repository this   type:     git   location: https://github.com/mhwombat/creatur.git-  tag:      5.3.2+  tag:      5.4.1  library   GHC-Options:      -Wall -fno-warn-orphans@@ -59,6 +59,8 @@                     ALife.Creatur.Genetics.Reproduction.Sexual,                     ALife.Creatur.Genetics.Reproduction.SimplifiedSexual,                     ALife.Creatur.Logger,+                    ALife.Creatur.Logger.SimpleLogger,+                    ALife.Creatur.Logger.SimpleRotatingLogger,                     ALife.Creatur.Namer,                     ALife.Creatur.Universe,                     ALife.Creatur.Task,
src/ALife/Creatur/Logger.hs view
@@ -16,80 +16,17 @@ module ALife.Creatur.Logger   (     Logger(..),-    SimpleRotatingLogger,-    mkSimpleRotatingLogger+    timestamp   ) where -import ALife.Creatur.Util (modifyLift, getLift)-import Control.Monad (when, unless)-import Control.Monad.State (StateT, gets)+import Control.Monad.State (StateT) import Data.Time (formatTime, getZonedTime)-import System.Directory (createDirectoryIfMissing, doesFileExist, renameFile) import System.Locale (defaultTimeLocale)  class Logger l where   -- | @'writeToLog' msg@ formats and writes a new log message.   writeToLog :: String -> StateT l IO () --- | A rotating logger.-data SimpleRotatingLogger = SimpleRotatingLogger {-    initialised :: Bool,-    directory :: FilePath,-    logFilename :: FilePath,-    expFilename :: FilePath,-    maxRecordsPerFile :: Int,-    recordCount :: Int-  } deriving (Show, Eq)---- | @'mkSimpleRotatingLogger' d prefix n@ creates a logger that will write to---   directory @d@. The log \"rotates\" (starts a new log file) every @n@---   records. Log files follow the naming convention @prefix@./k/, where /k/ ---   is the number of the last log record contained in the file. If logging---   has already been set up in @directory@, then logging will continue where---   it left off; appending to the most recent log file.-mkSimpleRotatingLogger :: FilePath -> String -> Int -> SimpleRotatingLogger-mkSimpleRotatingLogger d pre n = SimpleRotatingLogger False d fLog fExp n (-1)-  where fLog = d ++ "/" ++ pre ++ ".log"-        fExp = d ++ "/" ++ pre ++ ".exp"--instance Logger SimpleRotatingLogger where-  writeToLog msg = do-    initIfNeeded-    modifyLift bumpRecordCount-    getLift $ write' msg--initIfNeeded :: StateT SimpleRotatingLogger IO ()-initIfNeeded = do-  isInitialised <- gets initialised-  unless isInitialised $ modifyLift initialise--initialise :: SimpleRotatingLogger -> IO SimpleRotatingLogger-initialise logger = do-  createDirectoryIfMissing True (directory logger)-  let fExp = expFilename logger-  expFileExists <- doesFileExist fExp-  if expFileExists-    then do-      s <- readFile fExp-      return $ logger { initialised=True, recordCount=read s}-    else return $ logger { initialised=True, recordCount=0}--write' :: String -> SimpleRotatingLogger -> IO ()-write' msg logger = do-  timestamp <--      fmap (formatTime defaultTimeLocale "%y%m%d%H%M%S%z") getZonedTime-  appendFile (logFilename logger)-    $ timestamp ++ "\t" ++ msg ++ "\n"--bumpRecordCount :: SimpleRotatingLogger -> IO SimpleRotatingLogger-bumpRecordCount logger = do-  let n = 1 + recordCount logger-  when (0 == n `mod` maxRecordsPerFile logger) $ rotateLog logger-  writeFile (expFilename logger) (show n)-  return logger{ recordCount=n }--rotateLog :: SimpleRotatingLogger -> IO ()-rotateLog logger = do-  let f = logFilename logger-  renameFile f $ f ++ '.' : (show $ recordCount logger)-+timestamp :: IO String+timestamp =+  fmap (formatTime defaultTimeLocale "%y%m%d%H%M%S%z") getZonedTime
+ src/ALife/Creatur/Logger/SimpleLogger.hs view
@@ -0,0 +1,59 @@+------------------------------------------------------------------------+-- |+-- Module      :  ALife.Creatur.Logger.SimpleLogger+-- Copyright   :  (c) Amy de Buitléir 2011-2014+-- License     :  BSD-style+-- Maintainer  :  amy@nualeargais.ie+-- Stability   :  experimental+-- Portability :  portable+--+-- A simple rotating log, tailored to the needs of the Créatúr +-- framework.+--+------------------------------------------------------------------------+{-# OPTIONS_GHC -fno-warn-type-defaults #-}++module ALife.Creatur.Logger.SimpleLogger+  (+    SimpleLogger,+    mkSimpleLogger+  ) where++import ALife.Creatur.Util (getLift)+import ALife.Creatur.Logger (Logger(..), timestamp)+import Control.Conditional (unlessM)+import Control.Monad.IO.Class (liftIO)+import Control.Monad.State (StateT, gets, modify)+import System.Directory (createDirectoryIfMissing)+import System.FilePath (splitFileName)++-- | A rotating logger.+data SimpleLogger = SimpleLogger {+    initialised :: Bool,+    logFilename :: FilePath+  } deriving (Show, Eq)++-- | @'mkSimpleLogger' f@ creates a logger that will write to+--   file @f@.+mkSimpleLogger :: FilePath -> SimpleLogger+mkSimpleLogger f = SimpleLogger False f++instance Logger SimpleLogger where+  writeToLog msg = do+    initIfNeeded+    getLift $ write' msg++initIfNeeded :: StateT SimpleLogger IO ()+initIfNeeded =+  unlessM (gets initialised) initialise++initialise :: StateT SimpleLogger IO ()+initialise = do+  (d,_) <- fmap splitFileName $ gets logFilename+  liftIO $ createDirectoryIfMissing True d+  modify (\l -> l { initialised=True } )++write' :: String -> SimpleLogger -> IO ()+write' msg logger = do+  ts <- timestamp+  appendFile (logFilename logger) $ ts ++ "\t" ++ msg ++ "\n"
+ src/ALife/Creatur/Logger/SimpleRotatingLogger.hs view
@@ -0,0 +1,125 @@+------------------------------------------------------------------------+-- |+-- Module      :  ALife.Creatur.Logger.SimpleRotatingLogger+-- Copyright   :  (c) Amy de Buitléir 2011-2014+-- License     :  BSD-style+-- Maintainer  :  amy@nualeargais.ie+-- Stability   :  experimental+-- Portability :  portable+--+-- A simple rotating log, tailored to the needs of the Créatúr +-- framework.+--+------------------------------------------------------------------------+{-# OPTIONS_GHC -fno-warn-type-defaults #-}++module ALife.Creatur.Logger.SimpleRotatingLogger+  (+    Logger(..),+    SimpleRotatingLogger,+    mkSimpleRotatingLogger+  ) where++import ALife.Creatur.Util (getLift)+import ALife.Creatur.Logger (Logger(..), timestamp)+import Control.Conditional (whenM, unlessM)+import Control.Monad (when)+import Control.Monad.IO.Class (liftIO)+import Control.Monad.State (StateT, gets, modify)+import System.Directory (createDirectoryIfMissing, doesFileExist,+  renameFile)++-- | A rotating logger.+data SimpleRotatingLogger = SimpleRotatingLogger {+    initialised :: Bool,+    directory :: FilePath,+    logFilename :: FilePath,+    expFilename :: FilePath,+    maxRecordsPerFile :: Int,+    recordCount :: Int,+    logCount :: Int+  } deriving (Show, Eq)++-- | @'mkSimpleRotatingLogger' d prefix n@ creates a logger that will write to+--   directory @d@. The log \"rotates\" (starts a new log file) every @n@+--   records. Log files follow the naming convention @prefix@./k/, where /k/ +--   is the number of the last log record contained in the file. If logging+--   has already been set up in @directory@, then logging will continue where+--   it left off; appending to the most recent log file.+mkSimpleRotatingLogger :: FilePath -> String -> Int -> SimpleRotatingLogger+mkSimpleRotatingLogger d pre n =+  SimpleRotatingLogger False d fLog fExp n 0 0+  where fLog = d ++ "/" ++ pre ++ ".log"+        fExp = d ++ "/" ++ pre ++ ".exp"++instance Logger SimpleRotatingLogger where+  writeToLog msg = do+    initIfNeeded+    bumpRecordCount+    rotateLogIfNeeded+    getLift $ write' msg+    saveState++initIfNeeded :: StateT SimpleRotatingLogger IO ()+initIfNeeded =+  unlessM (gets initialised) initialise++initialise :: StateT SimpleRotatingLogger IO ()+initialise = do+  d <- gets directory+  liftIO $ createDirectoryIfMissing True d+  fExp <- gets expFilename+  whenM (liftIO $ doesFileExist fExp) readState+  modify (\l -> l { initialised=True } )+  debug "initialise"++debug :: String -> StateT SimpleRotatingLogger IO ()+debug s = do+  n <- gets recordCount+  k <- gets logCount+  getLift . write' $ "DEBUG " ++ s ++ ": n=" ++ show n ++ ": k=" ++ show k +  fExp <- gets expFilename+  whenM (liftIO $ doesFileExist fExp) $ do+    s' <- liftIO $ readFile fExp+    let (n',k') = read s' :: (Int,Int)+    getLift . write' $ "DEBUG2 " ++ s ++ ": n'=" ++ show n' ++ ": k'=" ++ show k' +  +readState :: StateT SimpleRotatingLogger IO ()+readState = do+  fExp <- gets expFilename+  s <- liftIO $ readFile fExp+  let (n,k) = read s+  modify (\l -> l { recordCount=n, logCount=k } )++saveState :: StateT SimpleRotatingLogger IO ()+saveState = do+  e <- gets expFilename+  n <- gets recordCount+  k <- gets logCount+  liftIO . writeFile e $ "(" ++ show n ++ "," ++ show k ++ ")"++write' :: String -> SimpleRotatingLogger -> IO ()+write' msg logger = do+  ts <- timestamp+  appendFile (logFilename logger) $ ts ++ "\t" ++ msg ++ "\n"++bumpRecordCount :: StateT SimpleRotatingLogger IO ()+bumpRecordCount = modify (\l -> l { recordCount=recordCount l + 1 })++rotateLogIfNeeded :: StateT SimpleRotatingLogger IO ()+rotateLogIfNeeded = do+  debug "rotateLogIfNeeded"+  n <- gets recordCount+  m <- gets maxRecordsPerFile+  when (n >= m) $ rotateLog+  +rotateLog :: StateT SimpleRotatingLogger IO ()+rotateLog = do+  debug "rotateLog"+  f <- gets logFilename+  n <- gets logCount+  let fPrev = f ++ '.' : show n+  getLift . write' $ "Continued in log " ++ show (n+1)+  liftIO $ renameFile f fPrev+  getLift . write' $ "Continued from log " ++ show n+  modify (\l -> l { recordCount=0, logCount=n+1 })
src/ALife/Creatur/Universe.hs view
@@ -59,6 +59,7 @@ import qualified ALife.Creatur.Database.FileSystem as FS import qualified ALife.Creatur.Database.CachedFileSystem as CFS import qualified ALife.Creatur.Logger as L+import qualified ALife.Creatur.Logger.SimpleLogger as SL import ALife.Creatur.Util (stateMap, shuffle) import Control.Monad.IO.Class (liftIO) import Control.Monad.Random (evalRandIO)@@ -273,7 +274,7 @@ data SimpleUniverse a = SimpleUniverse   {     suClock :: K.PersistentCounter,-    suLogger :: L.SimpleRotatingLogger,+    suLogger :: SL.SimpleLogger,     suDB :: FS.FSDatabase a,     suNamer :: N.SimpleNamer,     suChecklist :: CL.PersistentChecklist@@ -284,7 +285,7 @@   type Clock (SimpleUniverse a) = K.PersistentCounter   clock = suClock   setClock u c = u { suClock=c }-  type Logger (SimpleUniverse a) = L.SimpleRotatingLogger+  type Logger (SimpleUniverse a) = SL.SimpleLogger   logger = suLogger   setLogger u l = u { suLogger=l }   type AgentDB (SimpleUniverse a) = FS.FSDatabase a@@ -297,11 +298,11 @@   checklist = suChecklist   setChecklist u cl = u { suChecklist=cl } -mkSimpleUniverse :: String -> FilePath -> Int -> SimpleUniverse a-mkSimpleUniverse name dir rotateCount+mkSimpleUniverse :: String -> FilePath -> SimpleUniverse a+mkSimpleUniverse name dir   = SimpleUniverse c l d n cl   where c = K.mkPersistentCounter (dir ++ "/clock")-        l = L.mkSimpleRotatingLogger (dir ++ "/log/") name rotateCount+        l = SL.mkSimpleLogger (dir ++ "/log/" ++ name ++ ".log")         d = FS.mkFSDatabase (dir ++ "/db")         n = N.mkSimpleNamer (name ++ "_") (dir ++ "/namer")         cl = CL.mkPersistentChecklist (dir ++ "/todo")@@ -309,7 +310,7 @@ data CachedUniverse a = CachedUniverse   {     cuClock :: K.PersistentCounter,-    cuLogger :: L.SimpleRotatingLogger,+    cuLogger :: SL.SimpleLogger,     cuDB :: CFS.CachedFSDatabase a,     cuNamer :: N.SimpleNamer,     cuChecklist :: CL.PersistentChecklist@@ -320,7 +321,7 @@   type Clock (CachedUniverse a) = K.PersistentCounter   clock = cuClock   setClock u c = u { cuClock=c }-  type Logger (CachedUniverse a) = L.SimpleRotatingLogger+  type Logger (CachedUniverse a) = SL.SimpleLogger   logger = cuLogger   setLogger u l = u { cuLogger=l }   type AgentDB (CachedUniverse a) = CFS.CachedFSDatabase a@@ -333,11 +334,11 @@   checklist = cuChecklist   setChecklist u cl = u { cuChecklist=cl } -mkCachedUniverse :: String -> FilePath -> Int -> Int -> CachedUniverse a-mkCachedUniverse name dir rotateCount cacheSize+mkCachedUniverse :: String -> FilePath -> Int -> CachedUniverse a+mkCachedUniverse name dir cacheSize   = CachedUniverse c l d n cl   where c = K.mkPersistentCounter (dir ++ "/clock")-        l = L.mkSimpleRotatingLogger (dir ++ "/log/") name rotateCount+        l = SL.mkSimpleLogger (dir ++ "/log/" ++ name ++ ".log")         d = CFS.mkCachedFSDatabase (dir ++ "/db") cacheSize         n = N.mkSimpleNamer (name ++ "_") (dir ++ "/namer")         cl = CL.mkPersistentChecklist (dir ++ "/todo")