-- Hoogle documentation, generated by Haddock -- See Hoogle, http://www.haskell.org/hoogle/ -- | Framework for artificial life experiments. -- -- A software framework for automating experiments with artificial life. -- It provides a daemon which maintains its own "clock", schedules -- events, provides logging, and ensures that each agent gets its turn to -- use the CPU. You can use other applications on the computer at the -- same time without fear of interfering with experiments; they will run -- normally, just more slowly. See the tutorial at -- https://github.com/mhwombat/creatur-examples/raw/master/Tutorial.pdf -- for examples on how to use the Créatúr framework. -- -- About the name: "Créatúr" (pronounced kray-toor) is an Irish word -- meaning animal, creature, or an unfortunate person. @package creatur @version 5.9.4 -- | A simple rotating log, tailored to the needs of the Créatúr framework. module ALife.Creatur.Logger class Logger l writeToLog :: Logger l => String -> StateT l IO () timestamp :: IO String -- | TODO module ALife.Creatur.Genetics.Diploid -- | A diploid agent has two complete sets of genetic instructions. -- Instances of this class can be thought of as paired genes or paired -- instructions for building an agent. When two instructions in a pair -- differ, dominance relationships determine how the genes will be -- expressed in the agent. Minimal complete definition: -- express. class Diploid g where express x y = to $ gexpress (from x) (from y) express :: Diploid g => g -> g -> g expressMaybe :: Diploid g => Maybe g -> Maybe g -> Maybe g instance GDiploid U1 instance (GDiploid a, GDiploid b) => GDiploid (a :*: b) instance (GDiploid a, GDiploid b) => GDiploid (a :+: b) instance GDiploid a => GDiploid (M1 i c a) instance Diploid a => GDiploid (K1 i a) instance Diploid Bool instance Diploid Char instance Diploid Int instance Diploid Word instance Diploid Word8 instance Diploid Word16 instance Diploid Word32 instance Diploid Word64 instance Diploid Double instance Diploid a => Diploid [a] instance Diploid a => Diploid (Maybe a) instance (Diploid a, Diploid b) => Diploid (a, b) -- | ??? module ALife.Creatur.Genetics.Analysis class Analysable g where analyse = ganalyse . from analyse :: Analysable g => g -> String instance GAnalysable U1 instance (GAnalysable a, GAnalysable b) => GAnalysable (a :*: b) instance (GAnalysable a, GAnalysable b) => GAnalysable (a :+: b) instance GAnalysable a => GAnalysable (M1 i c a) instance Analysable a => GAnalysable (K1 i a) instance Analysable Bool instance Analysable Char instance Analysable Word8 instance Analysable Word16 instance Analysable a => Analysable [a] instance Analysable a => Analysable (Maybe a) instance (Analysable a, Analysable b) => Analysable (a, b) instance (Analysable a, Analysable b) => Analysable (Either a b) -- | Utility functions that don't fit anywhere else. module ALife.Creatur.Util -- | ilogBase n m returns the greatest integer not greater -- than the log base n of m. ilogBase :: (Integral a, Integral b, Integral c) => a -> b -> c -- | n isPowerOf m returns True if n is a -- power of m (i.e., if there exists an _integer_ k such that m^k = n) isPowerOf :: Integral a => a -> a -> Bool -- | isqrt n returns the greatest integer not greater than -- the square root of n. isqrt :: (Integral a, Integral b) => a -> b -- | perfectSquare n returns True if n is -- a perfect square (i.e., if there exists an _integer_ m such that m*m = -- n) perfectSquare :: Integral a => a -> Bool -- | Assuming xs is a sequence containing the elements of a matrix -- with k columns, cropRect (a,b) (c, d) k xs -- returns the elements of the submatrix from (a,b) in the upper -- left corner to (c,d) in the lower right corner). Note: Matrix -- indices begin at (0,0). -- -- Example: Suppose we have a 4x6 matrix and we want to -- extract the submatrix from (1,2) to (2,4), as illustrated below. -- --
--   a b c d e f
--   g h i j k l    --->   i j k
--   m n o p q r           o p q
--   s t u v w x
--   
-- -- We can represent the elements of the original matrix as -- ['a'..'x']. The elements of the submatrix are ['i', 'j', -- 'k', 'o', 'p', 'q'], or equivalently, "ijkopq". And that -- is what cropRect (1,2) (2,4) 6 ['a'..'x'] returns. cropRect :: (Int, Int) -> (Int, Int) -> [a] -> Int -> [a] -- | Assuming xs is a sequence containing the elements of a square -- matrix, cropSquare n xs returns the elements of the -- submatrix of size nxn, centred within the original -- matrix xs. -- -- Example: Suppose we have a 5x5 matrix and we want to -- extract the central 3x3 submatrix, as illustrated below. -- --
--   a b c d e
--   f g h i j            g h i
--   k l m n o    --->    l m n
--   p q r s t            q r s
--   u v w x y
--   
-- -- We can represent the elements of the original matrix as -- ['a'..'y']. The elements of the submatrix are ['g', 'h', -- 'i', 'l', 'm', 'n', 'q', 'r', 's'], or equivalently, -- "ghilmnqrs". And that is what cropSquare 3 -- ['a'..'y'] returns. cropSquare :: Int -> [a] -> [a] -- | replaceElement xs n x returns a copy of xs in -- which the nth element has been replaced with x. -- Causes an exception if xs has fewer than n+1 -- elements. Compare with safeReplaceElement. replaceElement :: [a] -> Int -> a -> [a] reverseLookup :: (Eq b) => b -> [(a, b)] -> Maybe a rotate :: [a] -> [a] -- | safeReplaceElement xs n x returns a copy of -- xs in which the nth element (if it exists) has been -- replaced with x. safeReplaceElement :: [a] -> Int -> a -> [a] -- | From http://www.haskell.org/haskellwiki/Random_shuffle shuffle :: RandomGen g => [a] -> Rand g [a] -- | Convert a list of bits to a string of 0s and 1s. boolsToBits :: [Bool] -> String -- | Show non-negative Integral numbers in binary. showBin :: (Integral a, Show a) => a -> ShowS stateMap :: Monad m => (s -> t) -> (t -> s) -> StateT s m a -> StateT t m a -- | The fromEither function takes a default value and an -- Either value. If the Either is Left, it returns -- the default value; otherwise, it returns the value contained in the -- Right. fromEither :: a -> Either e a -> a -- | Takes a list of Eithers and returns a list of all the -- Right values. catEithers :: [Either e a] -> [a] -- | Like modify, but the function that maps the old state to the new state -- operates in the inner monad. For example, -- --
--   s <- get
--   s' = lift $ f s
--   put s'
--   
-- -- can be replaced with -- --
--   modifyLift f
--   
modifyLift :: Monad m => (s -> m s) -> StateT s m () -- | Invoke a function in the inner monad, and pass the state as a -- parameter. Similar to modifyLift, but the function being invoked -- doesn't have a return value, so the state is not modified. For -- example, -- --
--   s <- get
--   s' = lift $ f s
--   
-- -- can be replaced with -- --
--   getLift f
--   
getLift :: Monad m => (s -> m ()) -> StateT s m () -- | Utilities for working with genes that are encoded as a sequence of -- bits, using a Binary Reflected Gray Code (BRGC). -- -- A Gray code maps values to codes in a way that guarantees that the -- codes for two consecutive values will differ by only one bit. This -- feature can be useful in evolutionary programming because the genes -- resulting from a crossover operation are likely to be similar to the -- inputs. This helps to ensure that offspring are similar to their -- parents, as any radical changes from one generation to the next are -- the result of mutation alone. module ALife.Creatur.Genetics.BRGCBool -- | A class representing anything which is represented in, and determined -- by, an agent's genome. This might include traits, parameters, "organs" -- (components of agents), or even entire agents. Instances of this class -- can be thought of as genes, i.e., instructions for building an agent. class Genetic g where put = gput . from get = do { a <- gget; return $ fmap to a } getWithDefault d = fmap (fromEither d) get put :: Genetic g => g -> Writer () get :: Genetic g => Reader (Either [String] g) getWithDefault :: Genetic g => g -> Reader g type Sequence = [Bool] type Writer = StateT Sequence Identity write :: Genetic x => x -> Sequence runWriter :: Writer () -> Sequence type Reader = StateT (Sequence, Int) Identity read :: Genetic g => Sequence -> Either [String] g runReader :: Reader g -> Sequence -> g -- | Return the entire genome. copy :: Reader Sequence -- | Return the portion of the genome that has been read. consumed :: Reader Sequence type DiploidSequence = (Sequence, Sequence) type DiploidReader = StateT ((Sequence, Int), (Sequence, Int)) Identity readAndExpress :: (Genetic g, Diploid g) => DiploidSequence -> Either [String] g runDiploidReader :: DiploidReader g -> DiploidSequence -> g -- | Read the next pair of genes from twin sequences of genetic -- information, and return the resulting gene (after taking into account -- any dominance relationship) and the remaining (unread) portion of the -- two nucleotide strands. getAndExpress :: (Genetic g, Diploid g) => DiploidReader (Either [String] g) getAndExpressWithDefault :: (Genetic g, Diploid g) => g -> DiploidReader g -- | Return the entire genome. copy2 :: DiploidReader DiploidSequence -- | Return the portion of the genome that has been read. consumed2 :: DiploidReader DiploidSequence instance GGenetic U1 instance (GGenetic a, GGenetic b) => GGenetic (a :*: b) instance (GGenetic a, GGenetic b) => GGenetic (a :+: b) instance GGenetic a => GGenetic (M1 i c a) instance Genetic a => GGenetic (K1 i a) instance Genetic Bool instance Genetic Char instance Genetic Word8 instance Genetic Word16 instance Genetic a => Genetic [a] instance Genetic a => Genetic (Maybe a) instance (Genetic a, Genetic b) => Genetic (a, b) instance (Genetic a, Genetic b) => Genetic (Either a b) -- | Utilities for working with genes that are encoded as a sequence of -- bytes, using a Binary Reflected Gray Code (BRGC). -- -- A Gray code maps values to codes in a way that guarantees that the -- codes for two consecutive values will differ by only one bit. This -- feature can be useful in evolutionary programming because the genes -- resulting from a crossover operation are likely to be similar to the -- inputs. This helps to ensure that offspring are similar to their -- parents, as any radical changes from one generation to the next are -- the result of mutation alone. module ALife.Creatur.Genetics.BRGCWord8 -- | A class representing anything which is represented in, and determined -- by, an agent's genome. This might include traits, parameters, "organs" -- (components of agents), or even entire agents. Instances of this class -- can be thought of as genes, i.e., instructions for building an agent. class Genetic g where put = gput . from get = do { a <- gget; return $ fmap to a } getWithDefault d = fmap (fromEither d) get put :: Genetic g => g -> Writer () get :: Genetic g => Reader (Either [String] g) getWithDefault :: Genetic g => g -> Reader g type Sequence = [Word8] type Writer = StateT Sequence Identity write :: Genetic x => x -> Sequence runWriter :: Writer () -> Sequence type Reader = StateT (Sequence, Int) Identity read :: Genetic g => Sequence -> Either [String] g runReader :: Reader g -> Sequence -> g -- | Return the entire genome. copy :: Reader Sequence -- | Return the portion of the genome that has been read. consumed :: Reader Sequence type DiploidSequence = (Sequence, Sequence) type DiploidReader = StateT ((Sequence, Int), (Sequence, Int)) Identity readAndExpress :: (Genetic g, Diploid g) => DiploidSequence -> Either [String] g runDiploidReader :: DiploidReader g -> DiploidSequence -> g -- | Read the next pair of genes from twin sequences of genetic -- information, and return the resulting gene (after taking into account -- any dominance relationship) and the remaining (unread) portion of the -- two nucleotide strands. getAndExpress :: (Genetic g, Diploid g) => DiploidReader (Either [String] g) getAndExpressWithDefault :: (Genetic g, Diploid g) => g -> DiploidReader g -- | Return the entire genome. copy2 :: DiploidReader DiploidSequence -- | Return the portion of the genome that has been read. consumed2 :: DiploidReader DiploidSequence -- | Write a Word8 value to the genome without encoding it putRawWord8 :: Word8 -> Writer () -- | Read a Word8 value from the genome without decoding it getRawWord8 :: Reader (Either [String] Word8) -- | Write a raw sequence of Word8 values to the genome putRawWord8s :: [Word8] -> Writer () -- | Read a raw sequence of Word8 values from the genome getRawWord8s :: Int -> Reader (Either [String] [Word8]) instance GGenetic U1 instance (GGenetic a, GGenetic b) => GGenetic (a :*: b) instance (GGenetic a, GGenetic b) => GGenetic (a :+: b) instance GGenetic a => GGenetic (M1 i c a) instance Genetic a => GGenetic (K1 i a) instance Genetic Bool instance Genetic Char instance Genetic Word8 instance Genetic Word16 instance Genetic a => Genetic [a] instance Genetic a => Genetic (Maybe a) instance (Genetic a, Genetic b) => Genetic (a, b) instance (Genetic a, Genetic b) => Genetic (Either a b) -- | Utilities for working with genes that are encoded as a sequence of -- 16-bit words, using a Binary Reflected Gray Code (BRGC). -- -- A Gray code maps values to codes in a way that guarantees that the -- codes for two consecutive values will differ by only one bit. This -- feature can be useful in evolutionary programming because the genes -- resulting from a crossover operation are likely to be similar to the -- inputs. This helps to ensure that offspring are similar to their -- parents, as any radical changes from one generation to the next are -- the result of mutation alone. module ALife.Creatur.Genetics.BRGCWord16 -- | A class representing anything which is represented in, and determined -- by, an agent's genome. This might include traits, parameters, "organs" -- (components of agents), or even entire agents. Instances of this class -- can be thought of as genes, i.e., instructions for building an agent. class Genetic g where put = gput . from get = do { a <- gget; return $ fmap to a } getWithDefault d = fmap (fromEither d) get put :: Genetic g => g -> Writer () get :: Genetic g => Reader (Either [String] g) getWithDefault :: Genetic g => g -> Reader g type Sequence = [Word16] type Writer = StateT Sequence Identity write :: Genetic x => x -> Sequence runWriter :: Writer () -> Sequence type Reader = StateT (Sequence, Int) Identity read :: Genetic g => Sequence -> Either [String] g runReader :: Reader g -> Sequence -> g -- | Return the entire genome. copy :: Reader Sequence -- | Return the portion of the genome that has been read. consumed :: Reader Sequence type DiploidSequence = (Sequence, Sequence) type DiploidReader = StateT ((Sequence, Int), (Sequence, Int)) Identity readAndExpress :: (Genetic g, Diploid g) => DiploidSequence -> Either [String] g runDiploidReader :: DiploidReader g -> DiploidSequence -> g -- | Read the next pair of genes from twin sequences of genetic -- information, and return the resulting gene (after taking into account -- any dominance relationship) and the remaining (unread) portion of the -- two nucleotide strands. getAndExpress :: (Genetic g, Diploid g) => DiploidReader (Either [String] g) getAndExpressWithDefault :: (Genetic g, Diploid g) => g -> DiploidReader g -- | Return the entire genome. copy2 :: DiploidReader DiploidSequence -- | Return the portion of the genome that has been read. consumed2 :: DiploidReader DiploidSequence -- | Write a Word16 value to the genome without encoding it putRawWord16 :: Word16 -> Writer () -- | Read a Word16 value from the genome without decoding it getRawWord16 :: Reader (Either [String] Word16) -- | Write a raw sequence of Word16 values to the genome putRawWord16s :: [Word16] -> Writer () -- | Read a raw sequence of Word16 values from the genome getRawWord16s :: Int -> Reader (Either [String] [Word16]) instance GGenetic U1 instance (GGenetic a, GGenetic b) => GGenetic (a :*: b) instance (GGenetic a, GGenetic b) => GGenetic (a :+: b) instance GGenetic a => GGenetic (M1 i c a) instance Genetic a => GGenetic (K1 i a) instance Genetic Bool instance Genetic Char instance Genetic Word8 instance Genetic Word16 instance Genetic a => Genetic [a] instance Genetic a => Genetic (Maybe a) instance (Genetic a, Genetic b) => Genetic (a, b) instance (Genetic a, Genetic b) => Genetic (Either a b) -- | Provides a mechanism to break apart and rejoin sequences of data. -- Inspired by DNA recombination in biology, this technique can be used -- to recombine "genetic" instructions for building artificial life. module ALife.Creatur.Genetics.Recombination -- | Cuts two lists at the specified location, swaps the ends, and splices -- them. This is a variation of cutAndSplice where n == m. crossover :: Int -> ([a], [a]) -> ([a], [a]) -- | Cuts two lists at the specified locations, swaps the ends, and splices -- them. The resulting lists will be: a[0..n-1] ++ b[m..] b[0..m-1] -- ++ a[n..] Here are some examples. Expression -- Result cutAndSplice 2 5 ("abcdef", "ABCDEF") -- ("abF","ABCDEcdef") cutAndSplice 3 1 ("abcd", "ABCDEFG") -- ("abcBCDEFG","Ad") cutAndSplice 4 4 ("abcdef", "ABCDEF") -- ("abcdEF","ABCDef") If n <= 0 or m <= 0, the corresponding -- input list will be completely transferred to the other. -- Expression Result cutAndSplice 0 4 ("abcdef", -- "ABCDEF") ("EF","ABCDabcdef") cutAndSplice (-2) 4 ("abcd", -- "ABCDEFGH") ("EFGH","ABCDabcd") cutAndSplice 5 0 ("abcdef", -- "ABCDEF") ("abcdeABCDEF","f") If n or m are greater than or -- equal to length of the corresponding list, that list will not be -- transferred. Expression Result cutAndSplice -- 10 0 ("abcdef", "ABCDEF") ("abcdefABCDEF","") cutAndSplice 0 0 -- ("", "ABCDEF") ("ABCDEF","") cutAndSplice :: Int -> Int -> ([a], [a]) -> ([a], [a]) -- | Mutates a random element in the list. mutateList :: (Random n, RandomGen g) => [n] -> Rand g [n] -- | Mutates a random element in one list in a pair. mutatePairedLists :: (Random n, RandomGen g) => ([n], [n]) -> Rand g ([n], [n]) randomOneOfList :: RandomGen g => [a] -> Rand g a randomOneOfPair :: RandomGen g => (a, a) -> Rand g a -- | Same as crossover, except that the location is chosen -- at random. randomCrossover :: RandomGen g => ([a], [a]) -> Rand g ([a], [a]) -- | Same as cutAndSplice, except that the two locations -- are chosen at random. randomCutAndSplice :: RandomGen g => ([a], [a]) -> Rand g ([a], [a]) -- | Performs an operation a random number of times. The probability of -- repeating the operation n times is p^n. repeatWithProbability :: RandomGen g => Double -> (b -> Rand g b) -> b -> Rand g b -- | Performs an operation with the specified probability. withProbability :: RandomGen g => Double -> (b -> Rand g b) -> b -> Rand g b -- | A simple rotating log, tailored to the needs of the Créatúr framework. module ALife.Creatur.Logger.SimpleLogger -- | A rotating logger. data SimpleLogger -- | mkSimpleLogger f creates a logger that will write to -- file f. mkSimpleLogger :: FilePath -> SimpleLogger instance Eq SimpleLogger instance Show SimpleLogger instance Logger SimpleLogger -- | A simple rotating log, tailored to the needs of the Créatúr framework. module ALife.Creatur.Logger.SimpleRotatingLogger class Logger l writeToLog :: Logger l => String -> StateT l IO () -- | A rotating logger. data SimpleRotatingLogger -- | 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 instance Eq SimpleRotatingLogger instance Show SimpleRotatingLogger instance Logger SimpleRotatingLogger -- | Provides a UNIX daemon to run an experiment using the Créatúr -- framework. module ALife.Creatur.Daemon -- | The work to be performed by a daemon. data Job s [Job] :: (s -> IO s) -> (s -> IO ()) -> (s -> SomeException -> IO s) -> StateT s IO () -> Int -> Job s -- | Operations to perform on startup. [onStartup] :: Job s -> s -> IO s -- | Operations to perform on shutdown. [onShutdown] :: Job s -> s -> IO () -- | Operations to perform if an exception occurs. [onException] :: Job s -> s -> SomeException -> IO s -- | Operations to perform repeatedly while running. [task] :: Job s -> StateT s IO () -- | Number of microseconds to sleep between invocations of -- task. [sleepTime] :: Job s -> Int data CreaturDaemon p s [CreaturDaemon] :: CreateDaemon p -> Job s -> CreaturDaemon p s [daemon] :: CreaturDaemon p s -> CreateDaemon p [job] :: CreaturDaemon p s -> Job s -- | Creates a simple daemon to run a job. The daemon will run under the -- login name. simpleDaemon :: Job s -> s -> CreateDaemon () -- | launch daemon state creates a daemon, which invokes -- daemon. *Note:* If user (in -- daemon) is Just "", the daemon will run under -- the login name. If user is Nothing, the daemon will -- run under the name of the executable file containing the daemon. launch :: CreaturDaemon p s -> IO () requestShutdown :: IO () -- | A state which persists between runs. module ALife.Creatur.Persistent data Persistent a -- | Creates a counter that will store its value in the specified file. mkPersistent :: a -> FilePath -> Persistent a getPS :: Read a => StateT (Persistent a) IO a putPS :: (Show a, Read a) => a -> StateT (Persistent a) IO () modifyPS :: (Show a, Read a) => (a -> a) -> StateT (Persistent a) IO () runPS :: Read a => (a -> b) -> StateT (Persistent a) IO b instance Eq a => Eq (Persistent a) instance Read a => Read (Persistent a) instance Show a => Show (Persistent a) -- | A simple task list which persists between runs. module ALife.Creatur.Checklist class Checklist t status :: Checklist t => StateT t IO Status markDone :: Checklist t => String -> StateT t IO () notStarted :: Checklist t => StateT t IO Bool done :: Checklist t => StateT t IO Bool setItems :: Checklist t => [String] -> StateT t IO () delete :: Checklist t => String -> StateT t IO () type PersistentChecklist = Persistent Status -- | Creates a counter that will store its value in the specified file. mkPersistentChecklist :: FilePath -> PersistentChecklist instance Checklist PersistentChecklist -- | Database interface for the Créatúr framework. module ALife.Creatur.Database -- | A database offering storage and retrieval for records. class Database d where type family DBRecord d keys :: Database d => StateT d IO [String] numRecords :: Database d => StateT d IO Int archivedKeys :: Database d => StateT d IO [String] lookup :: (Database d, Serialize (DBRecord d)) => String -> StateT d IO (Either String (DBRecord d)) lookupInArchive :: (Database d, Serialize (DBRecord d)) => String -> StateT d IO (Either String (DBRecord d)) store :: (Database d, Record (DBRecord d), Serialize (DBRecord d)) => DBRecord d -> StateT d IO () delete :: (Database d, Serialize (DBRecord d)) => String -> StateT d IO () class Record r key :: Record r => r -> String class (Record r) => SizedRecord r size :: SizedRecord r => r -> Int -- | A ridiculously simple database that stores each record in a separate -- file. The name of the file is the record's key. module ALife.Creatur.Database.FileSystem -- | A simple database where each record is stored in a separate file, and -- the name of the file is the record's key. data FSDatabase r -- | mkFSDatabase d (re)creates the FSDatabase in the -- directory d. mkFSDatabase :: FilePath -> FSDatabase r instance Eq (FSDatabase r) instance Show (FSDatabase r) instance Database (FSDatabase r) -- | A module containing private CachedFileSystem internals. Most -- developers should use CachedFileSystem instead. This module is subject -- to change without notice. module ALife.Creatur.Database.CachedFileSystemInternal -- | A simple database where each record is stored in a separate file, and -- the name of the file is the record's key. data CachedFSDatabase r [CachedFSDatabase] :: FSDatabase r -> [r] -> Int -> CachedFSDatabase r [database] :: CachedFSDatabase r -> FSDatabase r [cache] :: CachedFSDatabase r -> [r] [maxCacheSize] :: CachedFSDatabase r -> Int withFSDB :: Monad m => StateT (FSDatabase r) m a -> StateT (CachedFSDatabase r) m a fromCache :: Record r => String -> StateT (CachedFSDatabase r) IO (Maybe r) addToCache :: SizedRecord r => r -> StateT (CachedFSDatabase r) IO () deleteByKeyFromCache :: SizedRecord r => String -> StateT (CachedFSDatabase r) IO () deleteFromCache :: SizedRecord r => r -> StateT (CachedFSDatabase r) IO () trimCache :: SizedRecord r => StateT (CachedFSDatabase r) IO () trim :: SizedRecord r => Int -> [r] -> [r] listSize :: SizedRecord r => [r] -> Int -- | mkFSDatabase d (re)creates the FSDatabase in the -- directory d. mkCachedFSDatabase :: FilePath -> Int -> CachedFSDatabase r instance Eq r => Eq (CachedFSDatabase r) instance Show r => Show (CachedFSDatabase r) instance SizedRecord r => Database (CachedFSDatabase r) -- | A database that stores each record in a separate file and maintains a -- cache of recently-accessed records. The name of the file is the -- record's key. module ALife.Creatur.Database.CachedFileSystem -- | A simple database where each record is stored in a separate file, and -- the name of the file is the record's key. data CachedFSDatabase r -- | mkFSDatabase d (re)creates the FSDatabase in the -- directory d. mkCachedFSDatabase :: FilePath -> Int -> CachedFSDatabase r -- | Definitions used throughout the Créatúr framework. module ALife.Creatur -- | An artificial life species. All species used in Créatúr must be an -- instance of this class. class (Record a) => Agent a where agentId = key agentId :: Agent a => a -> AgentId isAlive :: Agent a => a -> Bool -- | A unique ID associated with an agent. type AgentId = String -- | The internal clock used by Créatúr is a simple counter. type Time = Int programVersion :: String -- | An internal simulation clock which persists between runs. This is a -- simple counter, completely independent from any system clock or -- hardware clock. The clock does not automatically advance, it only -- advances when incTime is called. In this way, the -- Créatúr framework will run consistently, treating all agents fairly, -- regardless of current processor load. It also ensures that data -- obtained from simulation runs on different machines with different CPU -- performance can still be meaningfully compared. module ALife.Creatur.Clock -- | A clock representing the time in a Créatúr universe. It is used to -- schedule events and ensure that each agent gets its fair share of the -- CPU. This clock is entirely separate from the system clock. It -- advances only when incTime is called. This allows -- Créatúr to run without being affected by other processes which might -- be using the CPU at the same time. class Clock c currentTime :: Clock c => StateT c IO Time incTime :: Clock c => StateT c IO () -- | A simple counter which persists between runs. module ALife.Creatur.Counter class Counter c current :: Counter c => StateT c IO Int increment :: Counter c => StateT c IO () type PersistentCounter = Persistent Int -- | Creates a counter that will store its value in the specified file. mkPersistentCounter :: FilePath -> PersistentCounter instance Counter PersistentCounter instance Clock PersistentCounter -- | Assigns a unique ID upon request. IDs generated by an Namer -- are guaranteed to be unique within a given universe, across all -- simulation runs. module ALife.Creatur.Namer class Namer n genName :: Namer n => StateT n IO String data SimpleNamer mkSimpleNamer :: String -> FilePath -> SimpleNamer instance Eq SimpleNamer instance Show SimpleNamer instance Namer SimpleNamer -- | A reproduction method for artificial lifeforms where: -- -- module ALife.Creatur.Genetics.Reproduction.Sexual -- | A species that reproduces, transmitting genetic information to its -- offspring. Minimal complete definition: all except mate. class Reproductive a where type family Strand a makeOffspring a b name = do { ga <- produceGamete a; gb <- produceGamete b; return $ build name (ga, gb) } produceGamete :: (Reproductive a, RandomGen r) => a -> Rand r (Strand a) build :: Reproductive a => AgentId -> (Strand a, Strand a) -> Either [String] a makeOffspring :: (Reproductive a, RandomGen r) => a -> a -> AgentId -> Rand r (Either [String] a) -- | A reproduction method for artificial lifeforms where: -- -- module ALife.Creatur.Genetics.Reproduction.SimplifiedSexual -- | A species that reproduces, transmitting genetic information to its -- offspring. Minimal complete definition: all except mate. class Reproductive a where type family Strand a makeOffspring a b name = do { g <- recombine a b; return $ build name g } recombine :: (Reproductive a, RandomGen r) => a -> a -> Rand r (Strand a) build :: Reproductive a => AgentId -> Strand a -> Either [String] a makeOffspring :: (Reproductive a, RandomGen r) => a -> a -> AgentId -> Rand r (Either [String] a) -- | Provides a habitat for artificial life. module ALife.Creatur.Universe -- | A habitat containing artificial life. class (Clock (Clock u), Logger (Logger u), Database (AgentDB u), Namer (Namer u), Checklist (Checklist u), Agent (Agent u), Record (Agent u), Agent u ~ DBRecord (AgentDB u)) => Universe u where type family Agent u type family Clock u type family Logger u type family AgentDB u type family Namer u type family Checklist u clock :: Universe u => u -> Clock u setClock :: Universe u => u -> Clock u -> u logger :: Universe u => u -> Logger u setLogger :: Universe u => u -> Logger u -> u agentDB :: Universe u => u -> AgentDB u setAgentDB :: Universe u => u -> AgentDB u -> u agentNamer :: Universe u => u -> Namer u setNamer :: Universe u => u -> Namer u -> u checklist :: Universe u => u -> Checklist u setChecklist :: Universe u => u -> Checklist u -> u data SimpleUniverse a data CachedUniverse a mkSimpleUniverse :: String -> FilePath -> SimpleUniverse a mkCachedUniverse :: String -> FilePath -> Int -> CachedUniverse a -- | The current "time" (counter) in this universe currentTime :: Universe u => StateT u IO Time -- | Increment the current "time" (counter) in this universe. incTime :: Universe u => StateT u IO () -- | Write a message to the log file for this universe. writeToLog :: Universe u => String -> StateT u IO () -- | Returns the list of agents in the population. agentIds :: Universe u => StateT u IO [AgentId] -- | Returns the list of (dead) agents in the archive. archivedAgentIds :: Universe u => StateT u IO [AgentId] -- | Returns the current size of the population. popSize :: Universe u => StateT u IO Int -- | Fetches the agent with the specified ID from the population. Note: -- Changes made to this agent will not "take" until store -- is called. getAgent :: (Universe u, Serialize (Agent u)) => AgentId -> StateT u IO (Either String (Agent u)) -- | Fetches the agent with the specified ID from the archive. getAgentFromArchive :: (Universe u, Serialize (Agent u)) => AgentId -> StateT u IO (Either String (Agent u)) -- | Fetches the agents with the specified IDs from the population. getAgents :: (Universe u, Serialize (Agent u)) => [AgentId] -> StateT u IO [Agent u] -- | If the agent is alive, adds it to the population (replacing the the -- previous copy of that agent, if any). If the agent is dead, places it -- in the archive. store :: (Universe u, Serialize (Agent u)) => Agent u -> StateT u IO () -- | Generate a unique name for a new agent. genName :: Universe u => StateT u IO AgentId -- | A program involving one agent. The input parameter is the agent. The -- program must return the agent (which may have been modified). type AgentProgram u = Agent u -> StateT u IO (Agent u) -- | Run a program involving one agent withAgent :: (Universe u, Serialize (Agent u)) => AgentProgram u -> AgentId -> StateT u IO () -- | A program involving multiple agents. The input parameter is a list of -- agents. The program must return a list of agents that have been -- *modified*. The order of the output list is not important. type AgentsProgram u = [Agent u] -> StateT u IO [Agent u] withAgents :: (Universe u, Serialize (Agent u)) => AgentsProgram u -> [AgentId] -> StateT u IO () isNew :: Universe u => AgentId -> StateT u IO Bool -- | Returns the current lineup of (living) agents in the universe. Note: -- Check for endOfRound and call -- refreshLineup if needed before invoking this function. lineup :: Universe u => StateT u IO [AgentId] -- | Returns true if no agents have yet their turn at the CPU for this -- round. startOfRound :: Universe u => StateT u IO Bool -- | Returns true if the lineup is empty or if all of the agents in the -- lineup have had their turn at the CPU for this round. endOfRound :: Universe u => StateT u IO Bool -- | Creates a fresh lineup containing all of the agents in the population, -- in random order. refreshLineup :: Universe u => StateT u IO () -- | Mark the current agent done. If it is still alive, it will move to the -- end of the lineup. markDone :: Universe u => AgentId -> StateT u IO () instance Eq a => Eq (CachedUniverse a) instance Show a => Show (CachedUniverse a) instance Eq (SimpleUniverse a) instance Show (SimpleUniverse a) instance (Agent a, Record a) => Universe (SimpleUniverse a) instance (Agent a, SizedRecord a) => Universe (CachedUniverse a) -- | Provides tasks that you can use with a daemon. These tasks handle -- reading and writing agents, and various other housekeeping chores, -- which reduces the amount of code you need to write. -- -- It’s also easy to write your own tasks, using these as a guide.) module ALife.Creatur.Task -- | A program involving one agent. The input parameter is the agent. The -- program must return the agent (which may have been modified). type AgentProgram u = Agent u -> StateT u IO (Agent u) -- | A program involving multiple agents. The input parameter is a list of -- agents. The program must return a list of agents that have been -- *modified*. The order of the output list is not important. type AgentsProgram u = [Agent u] -> StateT u IO [Agent u] -- | Run a program involving one agent withAgent :: (Universe u, Serialize (Agent u)) => AgentProgram u -> AgentId -> StateT u IO () withAgents :: (Universe u, Serialize (Agent u)) => AgentsProgram u -> [AgentId] -> StateT u IO () runNoninteractingAgents :: (Universe u, Serialize (Agent u)) => AgentProgram u -> StateT u IO () -> StateT u IO () -> StateT u IO () runInteractingAgents :: (Universe u, Serialize (Agent u)) => AgentsProgram u -> StateT u IO () -> StateT u IO () -> StateT u IO () simpleJob :: Universe u => Job u startupHandler :: Universe u => u -> IO u shutdownHandler :: Universe u => u -> IO () -- | Can be used as a startupHandler, shutdownHandler, startRoundProgram, -- or endRoundProgram doNothing :: Monad m => m () exceptionHandler :: Universe u => u -> SomeException -> IO u checkPopSize :: Universe u => (Int, Int) -> StateT u IO () requestShutdown :: Universe u => String -> StateT u IO ()