This version differs from the simple one in adding associated freeze
control signals ('clocks') to stateful entities to be able to pause
entire subnetworks without having to write all the low-level logic
explicitly. The clocks are fixed to signals upon their creation, and
the `withClock`

function can be used to specify the common clock for
the signals created in a given generator.

A clock signal affects `delay`

elements the following way: if the
clock signal is true, the delay works as usual, otherwise it remembers
its current output and throws away its current input. If we consider
signals to be functions of time (natural numbers), the behaviour of
delay can be described by the following function:

delay x0 s (t_start,clk) t_sample | t_start == t_sample = x0 | t_start < t_sample = if clk t_sample then s (t_sample-1) else delay x0 s (t_start (t_sample-1) | otherwise = error "stream doesn't exist yet"

A simple example to create counters operating at different rates using the same generator:

divisibleBy n x = x `mod` n == 0

counter = stateful 0 (+1)

drift = do time <- counter c1 <- withClock (divisibleBy 2 <$> time) counter c2 <- withClock (divisibleBy 3 <$> time) counter return ((,) <$> c1 <*> c2)

Note that if you want to slow down the drift system defined above, the naive approach might lead to surprising results:

slowDrift = do time <- counter withClock (divisibleBy 2 <$> time) drift

The problem is that the clocks are also slowed down, and their spikes
double in length. This may or may not be what you want. To overcome
this problem, we can define a clock oblivious edge detector to be used
within the definition of `drift`

:

edge = withClock (pure True) . transfer False (\b b' -> b && not b')

drift = do time <- counter t2 <- edge (divisibleBy 2 <$> time) t3 <- edge (divisibleBy 3 <$> time) c1 <- withClock t2 counter c2 <- withClock t3 counter return ((,) <$> c1 <*> c2)

This works because the `withClock`

function overrides any clock
imposed on the generator from outside.

- data Signal a
- data SignalGen a
- start :: SignalGen (Signal a) -> IO (IO a)
- external :: a -> IO (Signal a, a -> IO ())
- externalMulti :: IO (SignalGen (Signal [a]), a -> IO ())
- delay :: a -> Signal a -> SignalGen (Signal a)
- generator :: Signal (SignalGen a) -> SignalGen (Signal a)
- memo :: Signal a -> SignalGen (Signal a)
- until :: Signal Bool -> SignalGen (Signal Bool)
- withClock :: Signal Bool -> SignalGen a -> SignalGen a
- stateful :: a -> (a -> a) -> SignalGen (Signal a)
- transfer :: a -> (t -> a -> a) -> Signal t -> SignalGen (Signal a)
- noise :: MTRandom a => SignalGen (Signal a)
- getRandom :: MTRandom a => SignalGen a
- debug :: String -> SignalGen ()

# Documentation

A signal can be thought of as a function of type `Nat -> a`

,
where the argument is the sampling time, and the `Monad`

instance
agrees with the intuition (bind corresponds to extracting the
current sample).

Monad Signal | |

Functor Signal | |

Applicative Signal | |

Bounded t => Bounded (Signal t) | |

Enum t => Enum (Signal t) | |

Eq (Signal a) | |

Floating t => Floating (Signal t) | |

Fractional t => Fractional (Signal t) | |

Integral t => Integral (Signal t) | |

Num t => Num (Signal t) | |

Ord t => Ord (Signal t) | |

Real t => Real (Signal t) | |

Show (Signal a) |

A signal generator is the only source of stateful signals. It
can be thought of as a function of type `Nat -> a`

, where the
result is an arbitrary data structure that can potentially contain
new signals, and the argument is the creation time of these new
signals. It exposes the `MonadFix`

interface, which makes it
possible to define signals in terms of each other.

:: SignalGen (Signal a) | the generator of the top-level signal |

-> IO (IO a) | the computation to sample the signal |

Embedding a signal into an `IO`

environment. Repeated calls to
the computation returned cause the whole network to be updated, and
the current sample of the top-level signal is produced as a
result. This is the only way to extract a signal generator outside
the network, and it is equivalent to passing zero to the function
representing the generator.

A signal that can be directly fed through the sink function returned. This can be used to attach the network to the outer world.

An event-like signal that can be fed through the sink function
returned. The signal carries a list of values fed in since the
last sampling, i.e. it is constantly [] if the sink is never
invoked. The order of elements is reversed, so the last value
passed to the sink is the head of the list. Note that unlike
`external`

this function only returns a generator to be used within
the expression constructing the top-level stream, and this
generator can only be used once.

:: a | initial output at creation time |

-> Signal a | the signal to delay |

-> SignalGen (Signal a) | the delayed signal |

The `delay`

transfer function emits the value of a signal from
the previous superstep, starting with the filler value given in the
first argument. It can be thought of as the following function
(which should also make it clear why the return value is
`SignalGen`

):

delay x0 s t_start t_sample | t_start == t_sample = x0 | t_start < t_sample = s (t_sample-1) | otherwise = error "Premature sample!"

The way signal generators are extracted ensures that the error can never happen.

:: Signal (SignalGen a) | the signal of generators to run |

-> SignalGen (Signal a) | the signal of generated structures |

A reactive signal that takes the value to output from a signal generator carried by its input with the sampling time provided as the time of generation. It is possible to create new signals in the monad. It can be thought of as the following function:

generator g t_start t_sample = g t_sample t_sample

It has to live in the `SignalGen`

monad, because it needs to
maintain an internal state to be able to cache the current sample
for efficiency reasons. However, this state is not carried between
samples, therefore starting time doesn't matter and can be ignored.

:: Signal Bool | the boolean input signal |

-> SignalGen (Signal Bool) | a one-shot signal true only the first time the input is true |

A signal that is true exactly once: the first time the input
signal is true. Afterwards, it is constantly false, and it holds
no reference to the input signal. Note that `until`

always follows
the master clock, i.e. the fastest one, therefore it never creates
a long spike of `True`

.

withClock :: Signal Bool -> SignalGen a -> SignalGen aSource

Override the clock used in a generator. Note that clocks don't interact unless one is used in the definition of the other, i.e. it is possible to provide a fast clock within a generator with a slow associated clock.

:: a | initial internal state |

-> (t -> a -> a) | state updater function |

-> Signal t | input signal |

-> SignalGen (Signal a) |

A stateful transfer function. The current input affects the current output, i.e. the initial state given in the first argument is considered to appear before the first output, and can never be observed, and subsequent states are determined by combining the preceding state with the current output of the input signal using the function supplied. It is equivalent to the following expression:

transfer x0 f s =`mfix`

$ sig ->`liftA2`

f s`<$>`

`delay`

x0 sig