packages feed

rhine 0.2.0.0 → 0.3.0.0

raw patch · 4 files changed

+84/−109 lines, 4 filesdep ~dunaiPVP ok

version bump matches the API change (PVP)

Dependency ranges changed: dunai

API changes (from Hackage documentation)

+ FRP.Rhine.SyncSF: type BehaviorF m td a b = BehaviourF m td a b
+ FRP.Rhine.SyncSF.Except: keepFirst :: Monad m => SyncSF m cl a a
+ FRP.Rhine.SyncSF.Except: scaledTimer :: (Monad m, TimeDomain td, Fractional (Diff td), Ord (Diff td)) => Diff td -> BehaviorF (ExceptT () m) td a (Diff td)
+ FRP.Rhine.SyncSF.Except: timer :: (Monad m, TimeDomain td, Ord (Diff td)) => Diff td -> BehaviorF (ExceptT () m) td a (Diff td)
+ FRP.Rhine.SyncSF.Except: type BehaviorFExcept m td a b e = BehaviourFExcept m td a b e
- FRP.Rhine.SyncSF: average :: (Monad m, VectorSpace v, Floating (Groundfield v), Groundfield v ~ Diff (TimeDomainOf cl)) => Diff (TimeDomainOf cl) -> SyncSF m cl v v
+ FRP.Rhine.SyncSF: average :: (Monad m, VectorSpace v, Floating (Groundfield v), Groundfield v ~ Diff td) => Diff td -> BehaviourF m td v v
- FRP.Rhine.SyncSF: averageFrom :: (Monad m, VectorSpace v, Floating (Groundfield v), Groundfield v ~ Diff (TimeDomainOf cl)) => v -> Diff (TimeDomainOf cl) -> SyncSF m cl v v
+ FRP.Rhine.SyncSF: averageFrom :: (Monad m, VectorSpace v, Floating (Groundfield v), Groundfield v ~ Diff td) => v -> Diff td -> BehaviorF m td v v
- FRP.Rhine.SyncSF: averageLin :: (Monad m, VectorSpace v, Groundfield v ~ Diff (TimeDomainOf cl)) => Diff (TimeDomainOf cl) -> SyncSF m cl v v
+ FRP.Rhine.SyncSF: averageLin :: (Monad m, VectorSpace v, Groundfield v ~ Diff td) => Diff td -> BehaviourF m td v v
- FRP.Rhine.SyncSF: averageLinFrom :: (Monad m, VectorSpace v, Groundfield v ~ Diff (TimeDomainOf cl)) => v -> Diff (TimeDomainOf cl) -> SyncSF m cl v v
+ FRP.Rhine.SyncSF: averageLinFrom :: (Monad m, VectorSpace v, Groundfield v ~ Diff td) => v -> Diff td -> BehaviourF m td v v
- FRP.Rhine.SyncSF: derivative :: (Monad m, VectorSpace v, Groundfield v ~ Diff (TimeDomainOf cl)) => SyncSF m cl v v
+ FRP.Rhine.SyncSF: derivative :: (Monad m, VectorSpace v, Groundfield v ~ Diff td) => BehaviorF m td v v
- FRP.Rhine.SyncSF: derivativeFrom :: (Monad m, VectorSpace v, Groundfield v ~ Diff (TimeDomainOf cl)) => v -> SyncSF m cl v v
+ FRP.Rhine.SyncSF: derivativeFrom :: (Monad m, VectorSpace v, Groundfield v ~ Diff td) => v -> BehaviorF m td v v
- FRP.Rhine.SyncSF: integral :: (Monad m, VectorSpace v, Groundfield v ~ Diff (TimeDomainOf cl)) => SyncSF m cl v v
+ FRP.Rhine.SyncSF: integral :: (Monad m, VectorSpace v, Groundfield v ~ Diff td) => BehaviorF m td v v
- FRP.Rhine.SyncSF: integralFrom :: (Monad m, VectorSpace v, Groundfield v ~ Diff (TimeDomainOf cl)) => v -> SyncSF m cl v v
+ FRP.Rhine.SyncSF: integralFrom :: (Monad m, VectorSpace v, Groundfield v ~ Diff td) => v -> BehaviorF m td v v
- FRP.Rhine.SyncSF: type SyncSF m cl a b = MSF (ReaderT (TimeInfo cl) m) a b
+ FRP.Rhine.SyncSF: type BehaviourF m td a b = forall cl. td ~ TimeDomainOf cl => SyncSF m cl a b
- FRP.Rhine.SyncSF: weightedAverageFrom :: (Monad m, VectorSpace v, Groundfield v ~ Diff (TimeDomainOf cl)) => v -> SyncSF m cl (v, Groundfield v) v
+ FRP.Rhine.SyncSF: weightedAverageFrom :: (Monad m, VectorSpace v, Groundfield v ~ Diff td) => v -> BehaviorF m td (v, Groundfield v) v
- FRP.Rhine.SyncSF.Except: type SyncExcept m cl a b e = MSFExcept (ReaderT (TimeInfo cl) m) a b e
+ FRP.Rhine.SyncSF.Except: type BehaviourFExcept m td a b e = forall cl. td ~ TimeDomainOf cl => SyncExcept m cl a b e

Files

README.md view
@@ -1,82 +1,4 @@-# README+* README -------- -[![Build Status](https://travis-ci.org/turion/rhine.svg?branch=master)](https://travis-ci.org/turion/rhine)--Rhine is a library for synchronous and asynchronous Functional Reactive Programming (FRP).-It separates the aspects of clocking, scheduling and resampling-from each other, and ensures clock-safety on the type level.--Complex reactive programs often process data at different rates.-For example, games, GUIs and media applications-may output audio and video signals, or receive-user input at unpredictable times.-Coordinating these different rates is a hard problem in general.-If not enough care is taken, buffer underruns and overflows, space and time leaks,-accidental synchronisation of independent sub-systems,-and concurrency issues such as dead-locks may all occur.--Rhine tackles these problems by annotating-the signal processing components with clocks,-which hold the information when data will be-input, processed and output.-Different components of the signal network-will become active at different times, or work-at different rates. If components running under different clocks need to communicate, it-has to be decided when each component be--comes active ("scheduling"), and how data is-transferred between the different rates ("resampling").-Rhine separates all these aspects from each-other, and from the individual signal processing of each subsystem.-It offers a flexible API to all of them and implements several-reusable standard solutions. In the places-where these aspects need to intertwine, typing-constraints on clocks come into effect, enforcing clock safety.--A typical example, which can be run as `cabal run Demonstration`,-would be:--```-  -- | Create a simple message containing the time stamp since program start,-  --   for each tick of the clock.-  --   Since 'createMessage' works for arbitrary clocks (and doesn't need further input data),-  --   it is a 'Behaviour'.-  --   @td@ is the 'TimeDomain' of any clock used to sample,-  --   and it needs to be constrained in order for time differences-  --   to have a 'Show' instance.-  createMessage-    :: (Monad m, Show (Diff td))-    => String-    -> Behaviour m td String-  createMessage str-    =   timeInfoOf sinceStart >-> arr show-    >-> arr (("Clock " ++ str ++ " has ticked at: ") ++)--  -- | Output a message /every second/ (= every 1000 milliseconds).-  --   Let us assume we want to assure that 'printEverySecond'-  --   is only called every second,-  --   then we constrain its type signature with the clock @Millisecond 1000@.-  printEverySecond :: Show a => SyncSF IO (Millisecond 1000) a ()-  printEverySecond = arrMSync print--  -- | Specialise 'createMessage' to a specific clock.-  ms500 :: SyncSF IO (Millisecond 500) () String-  ms500 = createMessage "500 MS"---  ms1200 :: SyncSF IO (Millisecond 1200) () String-  ms1200 = createMessage "1200 MS"--  -- | Create messages every 500 ms and every 1200 ms,-  --   collecting all of them in a list,-  --   which is output every second.-  main :: IO ()-  main = flow $-    ms500 @@ waitClock **@ concurrently @** ms1200 @@ waitClock-    >-- collect -@- concurrently -->-    printEverySecond @@ waitClock--  -- | Uncomment the following for a type error (the clocks don't match):--  -- typeError = ms500 >>> printEverySecond-```+This is the main library.
rhine.cabal view
@@ -1,6 +1,6 @@ name:                rhine -version:             0.2.0.0+version:             0.3.0.0  synopsis: Functional Reactive Programming with type-level clocks @@ -44,7 +44,7 @@ source-repository this   type:     git   location: git@github.com:turion/rhine.git-  tag:      v0.2.0.0+  tag:      v0.3.0.0   library@@ -84,7 +84,7 @@    -- Other library packages from which modules are imported.   build-depends:       base         >= 4.7   && < 5-                    ,  dunai        == 0.2.0.*+                    ,  dunai        == 0.3.0.*                     ,  transformers >= 0.4   && < 0.6                     ,  time         >= 1.6   && < 1.7                     ,  free         >= 4.12  && < 4.13
src/FRP/Rhine/SyncSF.hs view
@@ -30,22 +30,30 @@  -- | A (synchronous) monadic stream function --   with the additional side effect of being time-aware,---   that is, reading the current 'TimeInfo' of the clock 'cl'.+--   that is, reading the current 'TimeInfo' of the clock @cl@. type SyncSF m cl a b = MSF (ReaderT (TimeInfo cl) m) a b --- | A synchronous signal is a |SyncSF| with no input required.+-- | A synchronous signal is a 'SyncSF' with no input required. --   It produces its output on its own. type SyncSignal m cl a = SyncSF m cl () a  -- | A (side-effectful) behaviour is a time-aware stream --   that doesn't depend on a particular clock.---   'td' denotes the |TimeDomain|.+--   @td@ denotes the 'TimeDomain'. type Behaviour m td a = forall cl. td ~ TimeDomainOf cl => SyncSignal m cl a  -- | Compatibility to U.S. american spelling. type Behavior  m td a = Behaviour m td a +-- | A (side-effectful) behaviour function is a time-aware synchronous stream+--   function that doesn't depend on a particular clock.+--   @td denotes the 'TimeDomain'.+type BehaviourF m td a b = forall cl. td ~ TimeDomainOf cl => SyncSF m cl a b +-- | Compatibility to U.S. american spelling.+type BehaviorF  m td a b = BehaviourF m td a b++ -- * Utilities to create 'SyncSF's from simpler data  -- TODO Test in which situations it makes sense not to change cl@@ -131,8 +139,8 @@ --   of the input, with initial offset @v0@. integralFrom   :: ( Monad m, VectorSpace v-     , Groundfield v ~ Diff (TimeDomainOf cl))-  => v -> SyncSF m cl v v+     , Groundfield v ~ Diff td)+  => v -> BehaviorF m td v v integralFrom v0 = proc v -> do   _sinceTick <- timeInfoOf sinceTick -< ()   sumFrom v0                         -< _sinceTick *^ v@@ -140,8 +148,8 @@ -- | Euler integration, with zero initial offset. integral   :: ( Monad m, VectorSpace v-     , Groundfield v ~ Diff (TimeDomainOf cl))-  => SyncSF m cl v v+     , Groundfield v ~ Diff td)+  => BehaviorF m td v v integral = integralFrom zeroVector  @@ -150,8 +158,8 @@ --   The input is initialised with @v0@. derivativeFrom   :: ( Monad m, VectorSpace v-     , Groundfield v ~ Diff (TimeDomainOf cl))-  => v -> SyncSF m cl v v+     , Groundfield v ~ Diff td)+  => v -> BehaviorF m td v v derivativeFrom v0 = proc v -> do   vLast         <- delay v0 -< v   TimeInfo {..} <- timeInfo -< ()@@ -160,8 +168,8 @@ -- | Numerical derivative with input initialised to zero. derivative   :: ( Monad m, VectorSpace v-     , Groundfield v ~ Diff (TimeDomainOf cl))-  => SyncSF m cl v v+     , Groundfield v ~ Diff td)+  => BehaviorF m td v v derivative = derivativeFrom zeroVector  -- | A weighted moving average signal function.@@ -173,9 +181,9 @@ --   whereas a weight of 0 outputs the current value. weightedAverageFrom   :: ( Monad m, VectorSpace v-     , Groundfield v ~ Diff (TimeDomainOf cl))+     , Groundfield v ~ Diff td)   => v -- ^ The initial position-  -> SyncSF m cl (v, Groundfield v) v+  -> BehaviorF m td (v, Groundfield v) v weightedAverageFrom v0 = feedback v0 $ proc ((v, weight), vAvg) -> do   let     vAvg' = weight *^ vAvg ^+^ (1 - weight) *^ v@@ -187,10 +195,10 @@ averageFrom   :: ( Monad m, VectorSpace v      , Floating (Groundfield v)-     , Groundfield v ~ Diff (TimeDomainOf cl))+     , Groundfield v ~ Diff td)   => v -- ^ The initial position-  -> Diff (TimeDomainOf cl) -- ^ The time scale on which the signal is averaged-  -> SyncSF m cl v v+  -> Diff td -- ^ The time scale on which the signal is averaged+  -> BehaviorF m td v v averageFrom v0 t = proc v -> do   TimeInfo {..} <- timeInfo -< ()   let@@ -202,9 +210,9 @@ average   :: ( Monad m, VectorSpace v      , Floating (Groundfield v)-     , Groundfield v ~ Diff (TimeDomainOf cl))-  => Diff (TimeDomainOf cl) -- ^ The time scale on which the signal is averaged-  -> SyncSF m cl v v+     , Groundfield v ~ Diff td)+  => Diff td -- ^ The time scale on which the signal is averaged+  -> BehaviourF m td v v average = averageFrom zeroVector  -- | A linearised version of 'averageFrom'.@@ -213,10 +221,10 @@ --   than the average time difference between two ticks. averageLinFrom   :: ( Monad m, VectorSpace v-     , Groundfield v ~ Diff (TimeDomainOf cl))+     , Groundfield v ~ Diff td)   => v -- ^ The initial position-  -> Diff (TimeDomainOf cl) -- ^ The time scale on which the signal is averaged-  -> SyncSF m cl v v+  -> Diff td -- ^ The time scale on which the signal is averaged+  -> BehaviourF m td v v averageLinFrom v0 t = proc v -> do   TimeInfo {..} <- timeInfo -< ()   let@@ -226,7 +234,7 @@ -- | Linearised version of 'average'. averageLin   :: ( Monad m, VectorSpace v-     , Groundfield v ~ Diff (TimeDomainOf cl))-  => Diff (TimeDomainOf cl) -- ^ The time scale on which the signal is averaged-  -> SyncSF m cl v v+     , Groundfield v ~ Diff td)+  => Diff td -- ^ The time scale on which the signal is averaged+  -> BehaviourF m td v v averageLin = averageLinFrom zeroVector
src/FRP/Rhine/SyncSF/Except.hs view
@@ -1,4 +1,8 @@-{-# LANGUAGE Arrows #-}+{-# LANGUAGE Arrows           #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE RankNTypes       #-}+{-# LANGUAGE TypeFamilies     #-}+ module FRP.Rhine.SyncSF.Except   ( module FRP.Rhine.SyncSF.Except   , module X@@ -22,6 +26,13 @@  type SyncExcept m cl a b e = MSFExcept (ReaderT (TimeInfo cl) m) a b e +type BehaviourFExcept m td a b e+  = forall cl. td ~ TimeDomainOf cl => SyncExcept m cl a b e++-- | Compatibility to U.S. american spelling.+type BehaviorFExcept m td a b e = BehaviourFExcept m td a b e++ -- | Commute the effects of the |ReaderT| and the |ExceptT| monad. commuteReaderExcept :: ReaderT r (ExceptT e m) a -> ExceptT e (ReaderT r m) a commuteReaderExcept a = ExceptT $ ReaderT $ \r -> runExceptT $ runReaderT a r@@ -57,3 +68,37 @@ --   and then throws an exception. step :: Monad m => (a -> m (b, e)) -> SyncExcept m cl a b e step f = MSFE.step $ lift . f++-- | Remembers and indefinitely outputs the first input value.+keepFirst :: Monad m => SyncSF m cl a a+keepFirst = safely $ do+  a <- try throwS+  safe $ arr $ const a+++-- | Throws an exception after the specified time difference,+--   outputting the remaining time difference.+timer+  :: ( Monad m+     , TimeDomain td+     , Ord (Diff td)+     )+  => Diff td+  -> BehaviorF (ExceptT () m) td a (Diff td)+timer diff = proc _ -> do+  time      <- timeInfoOf absolute -< ()+  startTime <- keepFirst           -< time+  let remainingTime = time `diffTime` startTime+  _         <- throwOn ()          -< remainingTime > diff+  returnA                          -< remainingTime++-- | Like 'timer', but divides the remaining time by the total time.+scaledTimer+  :: ( Monad m+     , TimeDomain td+     , Fractional (Diff td)+     , Ord        (Diff td)+     )+  => Diff td+  -> BehaviorF (ExceptT () m) td a (Diff td)+scaledTimer diff = timer diff >>> arr (/ diff)