{-# LANGUAGE TypeFamilies, GADTs, ScopedTypeVariables, TypeSynonymInstances, DeriveDataTypeable, NamedFieldPuns #-} module Control.Etage.Propagate ( propagate ) where import Control.Monad import Data.Typeable import Control.Etage.Internals import Control.Etage.Externals -- TODO: Implement delay in propagation (constant delay, random from some distribution) data PropagateNeuron from for = PropagateNeuron (PropagateOptions from for) deriving (Typeable) type PropagateOptions from for = NeuronOptions (PropagateNeuron from for) {-| An internal 'Neuron' which implements 'propagate'. -} instance (Impulse from, Impulse for) => Neuron (PropagateNeuron from for) where type NeuronFromImpulse (PropagateNeuron from for) = from type NeuronForImpulse (PropagateNeuron from for) = for data NeuronOptions (PropagateNeuron from for) = PropagateOptions { for ::[TranslatableFor for] } mkDefaultOptions = return PropagateOptions { for = undefined } grow options = return $ PropagateNeuron options live nerve (PropagateNeuron PropagateOptions { for }) = forever $ do i <- getForNeuron nerve mapM_ (\(TranslatableFor n) -> translateAndSend n i) for {-| It 'grow's an internal 'Neuron' which 'propagate's 'Impulse's from a given 'Nerve' to other 'Nerve's, 'translate'-ing as necessary. Be careful if you are 'propagate'-ing the same 'Nerve' multiple times as some 'Impulse's might already been 'propagate'd and thus are not available anymore to later 'propagate'd 'Nerve's. Just list all destination 'Nerve's the first time. Check 'attachTo' for a more high-level function (of 'Incubation') taking care of all the details (like branching 'Nerve's as necessary). Use this function only if you are dealing with 'grow'ing and 'attach'ing of 'Nerve's directly. -} propagate :: forall from for forConductivity. (Impulse from, Impulse for) => Nerve from AxonConductive for forConductivity -> [TranslatableFor from] -> IO () propagate _ [] = return () propagate from for = do -- we do not manage this neuron, it will be cleaned by RTS at program exit -- TODO: What if this is not the only thing the program is doing? Should we cleanup this threads at the end of Incubation, too? _ <- attach (\o -> o { for } :: NeuronOptions (PropagateNeuron for from)) (cross from) -- we use cross here so that in neuron we can behave as in normal neuron (use getForNeuron for example) return ()