------------------------------------------------------------------------ -- | -- Module : ALife.Creatur.Genetics.Reproduction.Sexual -- Copyright : (c) 2012-2021 Amy de Buitléir -- License : BSD-style -- Maintainer : amy@nualeargais.ie -- Stability : experimental -- Portability : portable -- -- 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. -- ------------------------------------------------------------------------ {-# LANGUAGE TypeFamilies #-} module ALife.Creatur.Genetics.Reproduction.Sexual ( Reproductive(..) ) where import ALife.Creatur (AgentId) import Control.Monad.Random (Rand, RandomGen) -- | A species that reproduces, transmitting genetic information to -- its offspring. Minimal complete definition: all except @mate@. class Reproductive a where -- | A sequence of hereditary information for an agent. -- The type signature for the agent's genome is -- (Strand a, Strand a). type Strand a -- | From the /two/ strands of the genetic information from this -- agent, creates a /single/ strand that will contribute to the -- child's genome. -- (This is analogous to creating either a single sperm or ova.) produceGamete :: RandomGen r => a -> Rand r (Strand a) -- | Builds an agent based on the genome provided, if it is possible -- to do so. build :: AgentId -> (Strand a, Strand a) -> Either [String] a -- | @'makeOffspring' (parent1, parent2) name@ uses the genetic -- information from @parent1@ and @parent2@ to produce a child with -- the agent ID @name@. The default implementation: -- -- 1. Calls @'produceGamete'@ to produce a single strand of genetic -- information from each parent. -- -- 1. Pairs the two strands to create a genome for the child. -- -- 1. Calls @'build'@ construct a child with this genome. makeOffspring :: RandomGen r => a -> a -> AgentId -> Rand r (Either [String] a) makeOffspring a a a b AgentId name = do Strand a ga <- a -> Rand r (Strand a) forall a r. (Reproductive a, RandomGen r) => a -> Rand r (Strand a) produceGamete a a Strand a gb <- a -> Rand r (Strand a) forall a r. (Reproductive a, RandomGen r) => a -> Rand r (Strand a) produceGamete a b Either [AgentId] a -> Rand r (Either [AgentId] a) forall (m :: * -> *) a. Monad m => a -> m a return (Either [AgentId] a -> Rand r (Either [AgentId] a)) -> Either [AgentId] a -> Rand r (Either [AgentId] a) forall a b. (a -> b) -> a -> b $ AgentId -> (Strand a, Strand a) -> Either [AgentId] a forall a. Reproductive a => AgentId -> (Strand a, Strand a) -> Either [AgentId] a build AgentId name (Strand a ga, Strand a gb)