-- 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 2.0.12 -- | 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 () -- | 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 Show SimpleRotatingLogger instance Logger SimpleRotatingLogger -- | 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] lookup :: (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 -- | Represents r FSDatabase (including agents, clock, logging facility, -- etc.) that can run within the Créatúr framework. 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 Show (FSDatabase r) instance Database (FSDatabase r) -- | Provides a UNIX daemon to run an experiment using the Créatúr -- framework. module ALife.Creatur.Daemon data Daemon s Daemon :: (s -> IO s) -> (s -> IO ()) -> (s -> SomeException -> IO s) -> StateT s IO () -> String -> Int -> Daemon s onStartup :: Daemon s -> s -> IO s onShutdown :: Daemon s -> s -> IO () onException :: Daemon s -> s -> SomeException -> IO s task :: Daemon s -> StateT s IO () username :: Daemon s -> String sleepTime :: Daemon s -> Int -- | launch username sleepTime state task creates a daemon -- running as username, which invokes task repeatedly, -- sleeping for sleepTime microseconds between invocations of -- task. launch :: Daemon s -> s -> IO () -- | Utility functions that don't fit anywhere else. module ALife.Creatur.Util -- | 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] -- | 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 -- | 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 -- | 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] stateMap :: Monad m => (s -> t) -> (t -> s) -> StateT s m a -> StateT t m a -- | Encoding schemes for genes. module ALife.Creatur.Genetics.CodeInternal -- | An encoding scheme. data Code a b Code :: Int -> [(a, [b])] -> Code a b cSize :: Code a b -> Int cTable :: Code a b -> [(a, [b])] -- | Encodes a value as a sequence of bits. encode :: Eq a => Code a b -> a -> Maybe [b] encodeNext :: Eq a => (Code a b, a) -> [b] -> [b] -- | Returns the value corresponding to a sequence of bits. decode :: Eq b => Code a b -> [b] -> Maybe a decodeNext :: Eq b => Code a b -> [b] -> (Maybe a, [b]) -- | Convert a list of bits to a string of 0s and 1s. asBits :: [Bool] -> String -- | Constructs a Gray code for the specified values, using the minimum -- number of bits required to encode all of the values. -- -- If the number of values provided is not a perfect square, some codes -- will not be used; calling decode with those values will -- return Nothing. You can find out if this will be the case by -- calling excessGrayCodes. For example mkGrayCode -- ['a','b','c'] would assign the code 00 to -- a, 01 to b, and -- 11 to c, leaving 10 unassigned. To -- avoid having unassigned codes, you can repeat a value in the input -- list so the example above could be modified to mkGrayCode -- ['a','a','b','c'], which would assign the codes 00 and -- 01 to a, 11 to b, and -- 10 to c. -- -- 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 will 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. mkGrayCode :: [a] -> Code a Bool -- | grayCodeLength n returns the number of bits required -- to encode n values. grayCodeLength :: Int -> Int -- | grayCodeCapacity n returns the number of values that -- can be encoded using n bits. The number of values that can be -- encoded in n bits is 2^n. grayCodeCapacity :: Int -> Int instance (Show a, Show b) => Show (Code a b) -- | Encoding schemes for genes. module ALife.Creatur.Genetics.Code -- | An encoding scheme. data Code a b -- | Constructs a Gray code for the specified values, using the minimum -- number of bits required to encode all of the values. -- -- If the number of values provided is not a perfect square, some codes -- will not be used; calling decode with those values will -- return Nothing. You can find out if this will be the case by -- calling excessGrayCodes. For example mkGrayCode -- ['a','b','c'] would assign the code 00 to -- a, 01 to b, and -- 11 to c, leaving 10 unassigned. To -- avoid having unassigned codes, you can repeat a value in the input -- list so the example above could be modified to mkGrayCode -- ['a','a','b','c'], which would assign the codes 00 and -- 01 to a, 11 to b, and -- 10 to c. -- -- 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 will 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. mkGrayCode :: [a] -> Code a Bool -- | Encodes a value as a sequence of bits. encode :: Eq a => Code a b -> a -> Maybe [b] encodeNext :: Eq a => (Code a b, a) -> [b] -> [b] -- | Returns the value corresponding to a sequence of bits. decode :: Eq b => Code a b -> [b] -> Maybe a decodeNext :: Eq b => Code a b -> [b] -> (Maybe a, [b]) -- | Convert a list of bits to a string of 0s and 1s. asBits :: [Bool] -> String -- | Definitions related to artificial genes. module ALife.Creatur.Genetics.Gene -- | A paired instruction for building an agent. class PairedGene g express :: PairedGene g => g -> g -> g -- | Read the next pair of PairedGenes from a two sequences of -- nucleotides, and return the resulting PairedGene (after taking -- into account any dominance relationship) and the remaining (unread) -- portion of the two nucleotide strands. decodeAndExpress :: (PairedGene g, Eq n) => Code g n -> ([n], [n]) -> (Maybe g, ([n], [n])) -- | 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 -- | Definitions use 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 Agent a 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 -- | 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 () data PersistentCounter -- | Creates a counter that will store its value in the specified file. mkPersistentCounter :: FilePath -> PersistentCounter instance Show PersistentCounter instance Clock PersistentCounter instance Counter PersistentCounter -- | Assigns a unique ID upon request. IDs generated by an -- AgentNamer are guaranteed to be unique within a given -- universe, across all simulation runs. module ALife.Creatur.AgentNamer class AgentNamer n genName :: AgentNamer n => StateT n IO AgentId data SimpleAgentNamer mkSimpleAgentNamer :: String -> FilePath -> SimpleAgentNamer instance AgentNamer SimpleAgentNamer -- | A reproduction method for artificial lifeforms where: * Each agent has -- a single strand of genetic information. * Each child has two -- parents. * Each parent contributes approximately half of its genetic -- information to the offspring. module ALife.Creatur.Genetics.Reproduction.Asexual -- | A species that reproduces, transmitting genetic information to its -- offspring. Minimal complete definition: all except mate. class Reproductive a where type family Base a makeOffspring a b name = do { g <- recombine a b; return $ build name g } recombine :: (Reproductive a, RandomGen r) => a -> a -> Rand r [Base a] build :: Reproductive a => AgentId -> [Base a] -> Maybe a makeOffspring :: (Reproductive a, RandomGen r) => a -> a -> AgentId -> Rand r (Maybe a) -- | A reproduction method for artificial lifeforms where: * Each agent has -- two strands of genetic information. * Each child has two -- parents. * Each parent contributes approximately half of its genetic -- information to the offspring. 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 Base 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 [Base a] build :: Reproductive a => AgentId -> ([Base a], [Base a]) -> Maybe a makeOffspring :: (Reproductive a, RandomGen r) => a -> a -> AgentId -> Rand r (Maybe a) -- | TODO: fill in module ALife.Creatur.Universe -- | A habitat containing artificial life. data Universe c l d n x a Universe :: c -> l -> d -> n -> x -> Universe c l d n x a _clock :: Universe c l d n x a -> c _logger :: Universe c l d n x a -> l _agentDB :: Universe c l d n x a -> d _namer :: Universe c l d n x a -> n _extra :: Universe c l d n x a -> x type SimpleUniverse a = Universe PersistentCounter SimpleRotatingLogger (FSDatabase a) SimpleAgentNamer () a mkSimpleUniverse :: String -> FilePath -> Int -> SimpleUniverse a agentDB :: Lens (Universe c_aggk l_aggl d_aggm n_aggn x_aggo a_aggp) (Universe c_aggk l_aggl d_agT5 n_aggn x_aggo a_agT6) d_aggm d_agT5 clock :: Lens (Universe c_aggk l_aggl d_aggm n_aggn x_aggo a_aggp) (Universe c_agTe l_aggl d_aggm n_aggn x_aggo a_agTf) c_aggk c_agTe logger :: Lens (Universe c_aggk l_aggl d_aggm n_aggn x_aggo a_aggp) (Universe c_aggk l_agTw d_aggm n_aggn x_aggo a_agTx) l_aggl l_agTw multiLookup :: (Serialize a, Database d, Record a, a ~ DBRecord d) => [AgentId] -> StateT d IO (Either String [DBRecord d]) extra :: Lens (Universe c_aggk l_aggl d_aggm n_aggn x_aggo a_aggp) (Universe c_aggk l_aggl d_aggm n_aggn x_agTn a_agTo) x_aggo x_agTn agentIds :: Database d => StateT (Universe c l d n x a) IO [String] addAgent :: (Serialize a, Database d, Record a, a ~ DBRecord d) => DBRecord d -> StateT (Universe c l d n x a) IO () storeOrArchive :: (Serialize a, Database d, Record a, Agent a, a ~ DBRecord d) => a -> StateT d IO () instance AgentNamer n => AgentNamer (Universe c l d n x a) instance Clock c => Clock (Universe c l d n x a) instance (Clock c, Logger l) => Logger (Universe c l d n x a) -- | TODO: fill in module ALife.Creatur.Universe.Task -- | A program for an agent which doesn't interact with other agents. The -- input parameter is the agent whose turn it is to use the CPU. The -- program must return the agent (which may have been modified). (The -- universe will then be updated with these changes.) type AgentProgram c l d n x a = a -> StateT (Universe c l d n x a) IO a -- | A program which allows an agent to interact with one or more of its -- neighbours. -- -- The input parameter is a list of agents. The first agent in the list -- is the agent whose turn it is to use the CPU. The rest of the list -- contains agents it could interact with. For example, if agents -- reproduce sexually, the program might check if the first agent in the -- list is female, and the second one is male, and if so, mate them to -- produce offspring. The input list is generated in a way that -- guarantees that every possible sequence of agents has an equal chance -- of occurring. -- -- The program must return a list of agents that it has modified. (The -- universe will then be updated with these changes.) The order of the -- output list is not important. type AgentsProgram c l d n x a = [a] -> StateT (Universe c l d n x a) IO [a] withAgent :: (Clock c, Logger l, Database d, Agent a, Serialize a, Record a, a ~ DBRecord d) => AgentProgram c l d n x a -> AgentId -> StateT (Universe c l d n x a) IO () withAgents :: (Clock c, Logger l, Database d, Agent a, Serialize a, Record a, a ~ DBRecord d) => AgentsProgram c l d n x a -> [AgentId] -> StateT (Universe c l d n x a) IO () runNoninteractingAgents :: (Clock c, Logger l, Database d, Agent a, Serialize a, Record a, a ~ DBRecord d) => AgentProgram c l d n x a -> StateT (Universe c l d n x a) IO () runInteractingAgents :: (Clock c, Logger l, Database d, Agent a, Serialize a, Record a, a ~ DBRecord d) => AgentsProgram c l d n x a -> StateT (Universe c l d n x a) IO () simpleDaemon :: Logger u => Daemon u startupHandler :: Logger u => u -> IO u shutdownHandler :: Logger u => u -> IO () exceptionHandler :: Logger u => u -> SomeException -> IO u