Copyright | (c) Ivan Perez 2014-2024 (c) George Giorgidze 2007-2012 (c) Henrik Nilsson 2005-2006 (c) Antony Courtney and Henrik Nilsson Yale University 2003-2004 |
---|---|
License | BSD-style (see the LICENSE file in the distribution) |
Maintainer | ivan.perez@keera.co.uk |
Stability | provisional |
Portability | non-portable (GHC extensions) |
Safe Haskell | Safe-Inferred |
Language | Haskell2010 |
Execution/simulation of signal functions.
SFs can be executed in two ways: by running them, feeding input samples one
by one, obtained from a monadic environment (presumably, IO
), or by passing
an input stream and calculating an output stream. The former is called
reactimation, and the latter is called embedding.
- Running:
Normally, to run an SF, you would use
reactimate
, providing input samples, and consuming the output samples in theIO
monad. This function takes over the program, implementing a "main loop". If you want more control over the evaluation loop (for instance, if you are using BearRiver in combination with a backend that also implements some main loop), you may want to use the lower-level API for reactimation (ReactHandle
,reactInit
,react
). - Embedding:
You can use
embed
for testing, to evaluate SFs in a terminal, and to embed an SF inside a larger system. The helper functionsdeltaEncode
anddeltaEncodeBy
facilitate producing input signals from plain lists of input samples.
This module also includes debugging aids needed to execute signal functions step by step, which are used by BearRiver's testing facilities.
Synopsis
- reactimate :: Monad m => m a -> (Bool -> m (DTime, Maybe a)) -> (Bool -> b -> m Bool) -> SF m a b -> m ()
- data ReactHandle a b
- reactInit :: IO a -> (ReactHandle a b -> Bool -> b -> IO Bool) -> SF Identity a b -> IO (ReactHandle a b)
- react :: ReactHandle a b -> (DTime, Maybe a) -> IO Bool
- embed :: Monad m => SF m a b -> (a, [(DTime, Maybe a)]) -> m [b]
- embedSynch :: forall m a b. (Monad m, MonadFail m) => SF m a b -> (a, [(DTime, Maybe a)]) -> SF m Double b
- deltaEncode :: Eq a => DTime -> [a] -> (a, [(DTime, Maybe a)])
- deltaEncodeBy :: (a -> a -> Bool) -> DTime -> [a] -> (a, [(DTime, Maybe a)])
- data FutureSF m a b
- evalAtZero :: SF Identity a b -> a -> (b, SF Identity a b)
- evalAt :: SF Identity a b -> DTime -> a -> (b, SF Identity a b)
- evalFuture :: SF Identity a b -> a -> DTime -> (b, SF Identity a b)
Reactimation
:: Monad m | |
=> m a | Initialization action |
-> (Bool -> m (DTime, Maybe a)) | Input sensing action |
-> (Bool -> b -> m Bool) | Actuation (output processing) action |
-> SF m a b | Signal function |
-> m () |
Convenience function to run a signal function indefinitely, using a IO actions to obtain new input and process the output.
This function first runs the initialization action, which provides the initial input for the signal transformer at time 0.
Afterwards, an input sensing action is used to obtain new input (if any) and the time since the last iteration. The argument to the input sensing function indicates if it can block. If no new input is received, it is assumed to be the same as in the last iteration.
After applying the signal function to the input, the actuation IO action is executed. The first argument indicates if the output has changed, the second gives the actual output). Actuation functions may choose to ignore the first argument altogether. This action should return True if the reactimation must stop, and False if it should continue.
Note that this becomes the program's main loop, which makes using this
function incompatible with GLUT, Gtk and other graphics libraries. It may
also impose a sizeable constraint in larger projects in which different
subparts run at different time steps. If you need to control the main loop
yourself for these or other reasons, use reactInit
and react
.
Low-level reactimation interface
data ReactHandle a b Source #
A reference to reactimate's state, maintained across samples.
reactInit :: IO a -> (ReactHandle a b -> Bool -> b -> IO Bool) -> SF Identity a b -> IO (ReactHandle a b) Source #
Initialize a top-level reaction handle.
Embedding
embed :: Monad m => SF m a b -> (a, [(DTime, Maybe a)]) -> m [b] Source #
Given a signal function and a pair with an initial input sample for the input signal, and a list of sampling times, possibly with new input samples at those times, it produces a list of output samples.
This is a simplified, purely-functional version of reactimate
.
embedSynch :: forall m a b. (Monad m, MonadFail m) => SF m a b -> (a, [(DTime, Maybe a)]) -> SF m Double b Source #
Synchronous embedding. The embedded signal function is run on the supplied input and time stream at a given (but variable) ratio >= 0 to the outer time flow. When the ratio is 0, the embedded signal function is paused.
deltaEncode :: Eq a => DTime -> [a] -> (a, [(DTime, Maybe a)]) Source #
Spaces a list of samples by a fixed time delta, avoiding unnecessary samples when the input has not changed since the last sample.
deltaEncodeBy :: (a -> a -> Bool) -> DTime -> [a] -> (a, [(DTime, Maybe a)]) Source #
deltaEncode
parameterized by the equality test.
Debugging / Step by step simulation
A wrapper around an initialized SF (continuation), needed for testing and debugging purposes.
evalAtZero :: SF Identity a b -> a -> (b, SF Identity a b) Source #
Evaluate an SF, and return an output and an initialized SF.
WARN: Do not use this function for standard simulation. This function is intended only for debugging/testing. Apart from being potentially slower and consuming more memory, it also breaks the FRP abstraction by making samples discrete and step based.
evalAt :: SF Identity a b -> DTime -> a -> (b, SF Identity a b) Source #
Evaluate an initialized SF, and return an output and a continuation.
WARN: Do not use this function for standard simulation. This function is intended only for debugging/testing. Apart from being potentially slower and consuming more memory, it also breaks the FRP abstraction by making samples discrete and step based.
evalFuture :: SF Identity a b -> a -> DTime -> (b, SF Identity a b) Source #
Given a signal function and time delta, it moves the signal function into the future, returning a new uninitialized SF and the initial output.
While the input sample refers to the present, the time delta refers to the future (or to the time between the current sample and the next sample).
WARN: Do not use this function for standard simulation. This function is intended only for debugging/testing. Apart from being potentially slower and consuming more memory, it also breaks the FRP abstraction by making samples discrete and step based.