{-| This branch is an experimental version of Elerea that does not build an actual graph of the dataflow network, just maintains a list of actions to update signals. Each signal consists of a mutable variable, an aging action and a finalising action. The variables can only be accessed through a sampling action, and they are only referred to in the corresponding aging and finalising action. These actions can be accessed through weak pointers that get invalidated when all other references to the corresponding variable are lost. This approach has both advantages and disadvantages. On the plus side, we don't have to create nodes for the applicative operations any more, because they can be encoded in the sampling actions in an efficient way. Also, since we have a list of independent actions to update the network, we can achieve nearly perfect parallelism, just like with a raytracer: all we need is a clever way of assigning actions to processing units. The downside is that we have to explicitly memoise the results of applicative operations in case they are used more than once. The modules below implement the basic idea in two variations: * "FRP.Elerea.Experimental.Simple" provides discrete signals, i.e. streams; * "FRP.Elerea.Experimental.Param" adds an extra parameter that's accessible to every node during the update, which can be used to provide a time step between samplings, or any other input necessary; * "FRP.Elerea.Experimental.Delayed" adds automatic delays, which violates referential transparency in a limited way, but improves the usability of the API when this doesn't matter. This module exports the delayed version along with a few utility functions. -} module FRP.Elerea.Experimental ( module FRP.Elerea.Experimental.Delayed , (-->) , edge , (==@), (/=@), (<@), (<=@), (>=@), (>@) , (&&@), (||@) ) where import Control.Applicative import FRP.Elerea.Experimental.Delayed infix 4 ==@, /=@, <@, <=@, >=@, >@ infixr 3 &&@ infixr 2 ||@ infix 2 --> {-| The 'edge' transfer function takes a bool signal and emits another bool signal that turns true only at the moment when there is a rising edge on the input. -} edge :: Signal p Bool -> SignalGen p (Signal p Bool) edge b = delay True b >>= \db -> return $ (not <$> db) &&@ b {-| The '-->' transfer function behaves as a latch on a 'Maybe' input: it keeps its state when the input is 'Nothing', and replaces it with the input otherwise. -} (-->) :: a -- ^ Initial output -> Signal p (Maybe a) -- ^ Maybe signal to latch on -> SignalGen p (Signal p a) x0 --> s = transfer x0 store s where store _ Nothing x = x store _ (Just x) _ = x {-| Point-wise equality of two signals. -} (==@) :: Eq a => Signal p a -> Signal p a -> Signal p Bool (==@) = liftA2 (==) {-| Point-wise inequality of two signals. -} (/=@) :: Eq a => Signal p a -> Signal p a -> Signal p Bool (/=@) = liftA2 (/=) {-| Point-wise comparison of two signals. -} (<@) :: Ord a => Signal p a -> Signal p a -> Signal p Bool (<@) = liftA2 (<) {-| Point-wise comparison of two signals. -} (<=@) :: Ord a => Signal p a -> Signal p a -> Signal p Bool (<=@) = liftA2 (<=) {-| Point-wise comparison of two signals. -} (>=@) :: Ord a => Signal p a -> Signal p a -> Signal p Bool (>=@) = liftA2 (>=) {-| Point-wise comparison of two signals. -} (>@) :: Ord a => Signal p a -> Signal p a -> Signal p Bool (>@) = liftA2 (>) {-| Point-wise OR of two boolean signals. -} (||@) :: Signal p Bool -> Signal p Bool -> Signal p Bool (||@) = liftA2 (||) {-| Point-wise AND of two boolean signals. -} (&&@) :: Signal p Bool -> Signal p Bool -> Signal p Bool (&&@) = liftA2 (&&)